The Community forums are being phased out in favor of a new Slack group.
Add your email address below to get an invitation to join the community slack group

Slack Signup
Newsletter Optin
Help Desk

Ranking options in order of preference

Labels

This Discussion is public

Notifications

The problem: 

I needed to create a form with a list of options that could be re-arranged into a preferred order by my users. Making this process as simple and fool proof as possible was of very high importance.

The Solution:

The solution turned out to be relatively simple and there is a working demo HERE. Essentially all you need to do is call the jQuery UI Sortable script and convert each of the Single Line Text fields into list items (and do a bit of re-styling). Here's now to do that:

Step 1: Create a new form.

Create a new form and add 3 fields to it to start with.

  • Field 1: HTML - call is something like "Start List" and leave the content blank
  • Field 2: Single Line Text - Give it a name and add a default value of 0 to it.
  • Field 3: HTML - as per field 1, call it something obvious like "End List" and leave the content blank.

Step 2: Form Settings.

  • General: Amend as required. As far i've found none of these make any difference to the list.
  • Form Actions: Nothing to do here.
  • Customise HTML: This is where we'll make the majority of the changes.

In the BEFORE FIELDS section add the following:

<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script src="https://s18718.pcdn.co/wp-includes/js/jquery/jquery.ui.touch-punch.js"></script>

And then underneath that add this:

<script type="text/javascript">
 jQuery(document).ready(function(){
 jQuery( '#sortable' ).sortable({
 stop: function () {
 var inputs = $('input.form-control');
 var nbElems = inputs.length;
 $('input.form-control').each(function(idx) {
 $(this).val(nbElems - idx);
 });
 }
 });
 });
 </script>

This script will 2 things to your form once published:

  1. It will call the jQuery UI Sortable script to make the 'list' sortable.
  2. It will update the value of each of the single line text fields when they are placed in a new position.

Note: It's probably worth mentioning that the above script applies the new values in REVERSE order as that was my requirement at the time. So if you have 10 fields in your list, the field at the top will have a value of 10, then 9 and so on.

Then in the HTML field, under the code that's in there currently, add this:

<div class="ListContainer">
<ol id="sortable">

Now for the Single Line Text field...

You need to add this line BEFORE any of the code in the box:

<li class="ui-state-default" id="listItem">

and then add this AFTER all of the code already in that box:

</li>

You can also (optionally) add in this line to give the list items a nice icon to help show that they are intended to be moved around:

<i class="fa fa-arrows" aria-hidden="true"></i>

This should be added just before this line: <label for="field_[key]" class="frm_primary_label">[field_name]

And lastly we need to add this to the final HTML Field:

</ol>
</div>

Now save your form.

You can now go back to the Form editor and duplicate the single line text field you have as many times as required to add more options to your list. Just make sure that you place the 'End List' HTML field AFTER all of the single line text fields.

Now all that needs to be done is adding some additional CSS to hide the text input field and generally make it look a bit nicer. You will probably need to play around with this CSS to make it work with your WordPress theme or other custom Formidable Styles that you've created.

Custom CSS:

/* Sortable List CSS */

#listItem {
 cursor: move;
 padding: 8px;
 margin: 0px 0px 3px 25px;
 border-radius: 3px;
 height: 45px;
 color: #333333 !important;
}

.ListContainer ol {
 white-space: nowrap;
 overflow-x: scroll;
 overflow-y: hidden;
}

.ListContainer {
 overflow-y: hidden;
 overflow-x: hidden;
}

/* Hide the Text Input */

li#listItem > .form-field > .form-control {
 display: none !important;
}

/* Re-style the Text Input Field */

#listItem > .form-field > .frm_style_formidable-style.with_frm_style .form-field {
 margin-bottom: 0px !important;
}

#listItem > .form-field > .frm_primary_label.control-label {
 padding: 0px !important;
}

#listItem > .form-field > .frm_primary_label {
 max-width: 200px !important;
}

/* Field Drag & Drop Icon CSS */

i.fa.fa-arrows {
 float: right;
 margin-top: 6px;
}

Place that CSS on the page that your form is going to go. As much as possible i've tried to use custom ID's to make sure that this CSS won't effect any other forms you have on your site if you need to add it to the Formidable Custom CSS area or to your theme's custom CSS area but make sure to test it out and make sure it doesn't break anything by mistake.

And that's it. It should look something like the screenshot below when you're finished.

If required you can  also combine this with the following code placed in a custom plugin or your theme's functions.php file to randomise the order that fields will display on the page when it loads (as per the demo):

add_filter('frm_get_paged_fields', 'get_extra_form_fields', 10, 3);
function get_extra_form_fields($fields, $form_id, $error=false){
 if($form_id == 25){ //change 25 to the id of the form to change
 shuffle($fields);
 }
 return $fields;
}

Note: Before you do this you will need to move the code in the HTML fields to the Before Fields and After Fields sections as they will also be put in at random positions and this will break everything big time. It also means that you can't have anything else in your form.

Screenshots are attached.

There is also a slightly more advanced version of this demo HERE.

Thanks

Chris

Screenshots attached.


Attachments:

Great tip! Thanks for sharing, Chris.

You do excellent functions with precise tutorials. A big thank-you.

Hi Chris!

Very helpful combination of jQuery UI + Formidable, but I have a question:

Can this also be implemented in Views? I want to reorder my results by drag and drop. I'm going to try figuring out but I don't know if this method can also adjust the order in the related table (I mean, by renumbering a field in the process), so the results stay in that order when reloading the view. Please enlight about this.

Hi Mauricio

You could certainly implement the drag and drop functionality into a view using the JQuery UI.

It would actually be a lot easier that implementing it into the form in many ways as you wouldn't have to edit the fields and add so much CSS.

In terms of saving the new order within the view, i'm not sure at this stage. I've only done some basic experiments with the form so far but i do intend on trying some things out with both the forms and views to see how easy it will be to save the order.

If you manage to get this working, or make any advances, let me know as i'd be interested to see how you get on.

All the best

Chris

Hi Chris! I'm with Mauricio, we are co-workers. I tried to make a new post with our advances in this theme but I couldn't do it, the system of Formidable Community says "Your entry appears to be spam!", I think it's because there was two urls in the post (one referencing this tutorial and the other to our demo), I removed it both but it won't let me post it anyway.

We really want to post the advances, so let me know how can I do it to work around this issue. Thanks.

Hi Julius,

You can post links in a message using the 'link' icon in the text editor.

Like THIS

Does that work for you?

Thanks

Chris

This is the post I was to write as new:

 


Attachments:

Hi Julius,

Ok so i've had a quick look at your screenshots and the demo.

The simple fixes:

The items jumping around when you scroll down the page is caused by CSS and the overflow rules. Try changing the overflow-x and overflow-y CSS to 'hidden' for the '.ListContainer ol'
The numbers display next to each item because we're turning them into an ordered list and your browser by default will add the numbers in. There are a couple of options to solve this:

Change the list from an ordered list (ol) to un-ordered list (ul). You'll need to go through the tutorial above and change all instances of  ol to ul.
The other solution is to use CSS to change the way a list item displays. You could change it to something simple like li { display: block; } or see what else works for you.

The other question you have about renumbering of the forms data is a little more complex if i've understood you correctly.

At the moment the JQuery in the demo will assign a value to each field, when you re-order the list. The number will replace the default value of 0 with the position of the item in the list. In your demo you have 8 items in the list so the item at the top will be given the value of '8' and then it will decrement accordingly down the list.

This only works for form fields though and is saved when you submit the form.

If you are applying the sort functionality to non-form elements in a view then the value won't be saved anywhere and the list order will be forgotten on page re-load.

In order to get the list to display in the saved order on page load you would need to somehow save the values assigned to each item.

Could you display a form in the view instead of just a normal list? That way you could assign values (which could be saved) and then potentially display the fields in value order somehow?

As i mentioned to Mauricio, i haven't looked into using it within a view quite yet so i'm really just thinking out loud at this stage.

Hopefully that gives you a good starting point though.

Chris

Also i just did a quick test on your demo and adding the following CSS will stop the jumping  around of the elements when dragged:

.ListContainer ol {
white-space: nowrap;
overflow-x: scroll;
overflow-y: hidden;
}

Thanks

Chris

Yes.

The problem number 3 is solved. I said it was a dumb question (not familiarized with ol, he!).

In the problem number 2, yes, I noticed now you said it. Setting one of the overflow-x (or y) properties to hidden and the other to scroll fixes the jumping problem... but it shows an ugly and useless scroll bar at the bottom (or right). I wonder why, there must be a fix for this because I see many dragging lists in the web and none has this problem.

For the main issue, the thing is it would be nice to work with the captured values in the form, but using the Formidable View. I mean, in your original tutorial, there are pre-captured values (each candidate's name), and we are changing the order of fields in the form.

My intention is to work in a View with the previously entered values. As an example: you enter a Task name in the form, and let's say the form assigns a number automatically (no matter the order, that's only to sort) in a Number field.

Then, when displaying the view, we can drag the order of the list and the javascript function has to change the Number field order according to the new display order. That is using the function for altering that field in the form. I'm sure I once saw a method (I think it's really simple) to do this but I lost track of that post.

Of course, after changing this order internally, the next time we display the list it will show the new order according to the Number field.

Would you know something about this? Did I explain it well?

Hi!

We tried to add this code to the script:
$("#field_68").change(function(){
$(this).val(nbElems - idx);
});

Because 68 is the Number field, thinking that would change the current field value with the current calculation order, and nothing happened. But I think that may be closer to the desired result.

I love how this looks, but I cannot, for the life of me, get it to work. I am noticing on your example, that you have input with class "form-control" I do not. I have no idea how to get the input to have a class identifier at all. Any input?

Hi Danielle

Do you have a link to your form?

You can use any class that's common to the fields you wish to re-order.

You can add any class name to these fields in the Settings > Customise HTML section of Formidable.

Hope that helps.

Chris

Hi Danielle,

You could also replace "input.form-control" with "input[type=text]".

You'll need to replace it in 2 places in the JS script and also once in the CSS.

Thanks

Chris

Edit to update: I was able to get the class updated on the input field, however I'm still not able to get it dragging. I have no idea what I'm doing wrong....

http://liguoritravel.com/200-2/

 

When I get that working I'll move it to my actual forms.

Hi Danielle,

I think it's because you have:

<div class="ListContainer">
<ol id="sortable1" class="connectedSortable">

instead of:

<div class="ListContainer">
<ol id='sortable' class="topSection">

Try replacing those and see how you get on.

Thanks

Chris

No, it didn't help... I've tried editing to what you wrote in the blog, to your screenshots, and to what you have in your demo. I have no idea what I'm doing wrong. Javascript and I really just do not get along. I have whatever the opposite of the Midas touch is with it! LOL

Hi Danielle,

After having had another look at your site i've noticed JS error which is why it's not working.

For some reason the jQuery UI isn't being loaded and therefore the sortable classes aren't being added to your form elements. This resource isn't being loaded:

<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

It's hard to say exactly what's causing the issue but it's probably another plugin or the theme.

You can check your plugins / theme for any code which may be dequeuing the UI sortable script by deactivating the plugins one at a time and testing it to see if that's the issue.

Sorry if that's not that much help.

Chris

No that was super helpful!! I found the plugin that was disabling it. I'll have to do some research to find out if there is a way I could have both plugins since they both provide value to the website. Thank you so much!

 

 

Hi,

Did anyone work out how to write sorted changes to the Formidable database?

Seems like a really useful feature to be able to drag, sort and save entries in a view.

If anyone who's tried this has got any insight that would be great. Beyond getting the drag and sort working, saving the changes so the entries stay in that display order is a bit beyond me.

Thanks!

Rich

Hi Rich,

The demo that we built is created using a form and single line text fields that can be re-ordered.

Each single line text field is given an initial value of '0' until the list is reordered. The JS snippet then assigns a decreasing value to each item in the list.

For example, if you have 10 items in your list, the item at the top will be given a value of 10, item 2 then has a value of 9 and so on.

We haven't experimented that much with displaying the results in a view but you could sort the results so that they display in decreasing value and would therefore match what was submitted in the form.

The difficulty then comes with editing a saved entry. To re-order the list from within the view you would need to find a way of writing the new values back to the DB or you could look at editing it by updating the original entry within the form (not from the view) which may be easier.

You would need to find a way to make sure the form displays the list in the order in which it was saved though but i think that would be easier than trying to submit new values from a view.

Now i've written that out I'm not sure if helps much but hopefully it will point you in the right direction.

We do plan on doing some more work on this feature, along with a few other Formidable extensions we're working on, but fitting them in and around client work is always difficult so we don't have an ETA on it quite yet.

Thanks

Chris

Hi Chris,

Thanks, yeah we're on the same page. I'm looking to create a way of giving users a way or re-organising entries they've already added and saving that order.

I've worked out how to do the dragging and re-ordering, just not how to save that to the formidable database so that it affects the display order without adding additional columns to the wp_frm_items_meta table.

This is a simple demo, but it's basically what I'm trying to do (http://wrktp.com/wp-content/plugins/dsktp-drag-drop/index.php)

When an entry from a form is created it is stored in wp_frm_items table, but the details of the entry are stored in wp_frm_item_metas (i.e. the contents of most of the non-core fields).

The code required to do that is beyond me at the moment, but I'm working on a brief for the prototype so that I can get a quote from a php /mysql developer to do it. Whether or not I go ahead depends on the quote, but there are so many ways this can be used to give more interactivity to a site it seems like a worthwhile endeavour.

Rich

Hi Rich,

Ok i'm with you.

I actually don't think this would be too difficult to do (famous last words).

The formidable API add-on allows you to send (or receive) data via a URL.

JQuery UI Sortable includes a serialize method to assign values to the elements which you could then send to update the form entry using the API with something like this:

$('#element').sortable({
axis: 'y',
update: function (event, ui) {
var data = $(this).sortable('serialize');

// POST to server using $.post or $.ajax
$.ajax({
data: data,
type: 'POST',
url: '/your/url/here'
});
}
});

Note: This is just theoretical but i don't see an initial reason why it wouldn't work. Might need some adjustments though.

If i get time i might have a look at this in some more detail later today.

Thanks

Chris

Also here is some info on updating an entry using the API add-on:

https://formidableforms.com/knowledgebase/formidable-api/#kb-update-an-entry

Thanks

Chris

Hi Chris,

Thanks! Ok, as you say I need to get some work out of the way this morning, but have created a test site to build this prototype so will spend some time on it this afternoon. Thanks for your help so far!

Rich

Hi, this looked like exactly what I needed. I set up my form, the fields looked good and dragged beautifully, but when I test it and look at the entry results, they are all zero. I've double checked my codes, started from scratch, tried turning off all the other plug-ins, but no luck. My site goes live in a couple days, so would really love some help. Any ideas of where to start would be appreciated.

Hi There

I finally got this to work by using a few hacks.  Not all the css code seems to be working for me within the styles option and also if I try put it in to my childs css stylesheet.

But within the text field if I set it to Read Only and hide the label position it works.

The only thing I cannot get to work is the i.fa.fa-arrows.  It does display on the top of the bar when the Label Position is set to default.  But I need to hide the label.

Can you advise how I can get the symbol to appear within the field? Please refer to the attached screenshots.

UPDATE:
Got it to work for me, I had to change to code below

/* Field Drag & Drop Icon CSS */

i.fas.fa-arrows-alt {
float: left;
margin-top: 6px;
color: #222222;
}


Attachment:

I have added two ranking questions in to one form and the second one does not work.  It gives you the hover but will not allow you to drag.  Is this because you can only have one per form?  If so how do I get around this.

UPDATE - FIXED:

added an additional sortable-id in the third line:

jQuery(document).ready(function(){
jQuery( '#sortable , #sortable-2' ).sortable({
stop: function () {
var inputs = $('input.form-control');
var nbElems = inputs.length;
$('input.form-control').each(function(idx) {
$(this).val(nbElems - idx);
});
}
});
});

and then in the starting HTML block for the second rank question:

Discussion closed.