Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Ben McKean 272 posts 549 karma points
    May 20, 2015 @ 09:38
    Ben McKean
    0

    Forms custom data type - repeatable text box

    Hi,

    Does anybody have any experience of developing a custom data type that is repeatable text box?

    To give some context, this is for a job application form and I want to give users the ability to add employment history with the following fields:

    Date Employer Position Duties Salary Reason for leaving

    I'd like the user to be able to add rows to be able to add multiple entries with a nice + icon.

    Does anybody know or could point me in the direction of how to best achieve this please?

    Thanks

  • Dave Woestenborghs 3504 posts 12133 karma points MVP 8x admin c-trib
    May 20, 2015 @ 09:41
  • Ben McKean 272 posts 549 karma points
    May 20, 2015 @ 09:49
    Ben McKean
    0

    Thanks, I could imagine how that would work but not sure how I'd integrate it into Forms?!

  • Dave Woestenborghs 3504 posts 12133 karma points MVP 8x admin c-trib
    May 20, 2015 @ 09:50
    Dave Woestenborghs
    0

    Ah sorry,

    I missed that your question was about forms. I think the only option is to create it your self.

    Dave

  • Comment author was deleted

    May 20, 2015 @ 10:11

    Hey Ben, I'll post an example of a custom fieldtype in the afternoon, that should get you started

  • Ben McKean 272 posts 549 karma points
    May 20, 2015 @ 10:14
    Ben McKean
    0

    Great, thanks Tim!

  • Comment author was deleted

    May 20, 2015 @ 15:33

    So each fieldtype consists of a definition https://gist.github.com/TimGeyssens/38bd409d4c8c288e6555 (so a class that inherits from FieldType) and a view https://gist.github.com/TimGeyssens/29e0d52d4bc29b202289

    The view needs to live in \Views\Partials\Forms\Fieldtypes\FieldType.[fieldtypename].cshtml

    As you'll notice the concept of a field in Forms doesn't really allow the type of thing you are planning to do so not sure if it is even possible, I'll do a quick test and get back to you

  • Comment author was deleted

    May 20, 2015 @ 15:53

    So if I understand correctly you want this type of control http://plnkr.co/edit/u0yVCmXybdlK7SMyR8Fl?p=preview in your form ?

  • Comment author was deleted

    May 20, 2015 @ 15:54

    Think it will be possible to only downside will be that the entries viewer will see it as a single field so you'll get a lot of data in a single field... 

  • Ben McKean 272 posts 549 karma points
    May 20, 2015 @ 15:59
    Ben McKean
    0

    Thanks for looking at this. Yes, thats right

  • Comment author was deleted

    May 20, 2015 @ 16:00

    Ok working on a prototype should be finished tomorrow morning, will have all details for you then

  • Comment author was deleted

    May 20, 2015 @ 16:15

    Ok so first step would look like this http://plnkr.co/edit/u0yVCmXybdlK7SMyR8Fl?p=preview you would have your control populating a hidden input with json... we'll then grab that json on the server side and process it

  • Comment author was deleted

    May 20, 2015 @ 16:54

    Here is the example project https://www.dropbox.com/s/u0jltiigg64khm2/FormsRepeatableFieldType.zip?dl=0 just tested and it works :)

    You'll need to drop the assembly in the bin and the view in \Views\Partials\Forms\Fieldtypes

    The designer will also need a view but that is just some html

    Let me know if you have any questions but that should get you started

  • Ben McKean 272 posts 549 karma points
    May 21, 2015 @ 10:03
    Ben McKean
    0

    Hi Tim,

    Thank you so much for this.

    I've managed to drop it all in and get it working! The fields I've using are actually more, 6 rather than 3. So I've added them this way.

    There are also 3 other repeatable field types on the form so I'm sure I'll be able to replicate what you've done for those.

    As you said, all values are stored in one field in Forms, which is fine but is there anyway that rows can be seperated (Dates is the first field)? The users will likely be exporting to CSV or HTML and at the moment they're continuous, see below. A line break/carriage return would suffice. Is there anyway I can do this?

    Dates: ghfj, NameAndAddressOfEmployer: ghfj, JobTitle ghfj, Duties gfhj, RateOfPay gfhjghf, ReasonForLeaving jghfj, Dates: ghfjj, NameAndAddressOfEmployer: j, JobTitle jj, Duties jj, RateOfPay j, ReasonForLeaving j

     

    Thanks again

  • Comment author was deleted

    May 21, 2015 @ 10:54

    Yeah in the ToString method of the Role model, just add a line break at the end

  • Ben McKean 272 posts 549 karma points
    May 21, 2015 @ 11:10
    Ben McKean
    0

    Ok great, that works fine for exporting to HTML but I think there is currently a bug with exporting to CSV for any fields with comma seperated vlaues not being enclosed in speech marks so think that will be fixed in due course here http://issues.umbraco.org/issue/CON-726.

    Here is a screen shot of it in action in the backend, thanks for your help!

     

  • Comment author was deleted

    May 21, 2015 @ 11:24

    yeah that bug is fixed and will be part of maintenance release going out today :)

  • Ben McKean 272 posts 549 karma points
    May 22, 2015 @ 12:28
    Ben McKean
    0

    I've got it all working apart from one last thing that I could do with your help on please.

    It breaks if any of the repeatable fields are empty. Where would I put the code to handle this?

  • Comment author was deleted

    May 22, 2015 @ 13:14

    What is the error you get? It's probably in the fieldtype class

    Where it has this code

    public override IEnumerable<object> ConvertToRecord(Field field, IEnumerable<object> postedValues, HttpContextBase context)
            {
                var roles = JsonConvert.DeserializeObject<IEnumerable<Role>>(postedValues.First().ToString());
     
                List<Object> vals = new List<object>();
     
                foreach(var role in roles)
                {
                    vals.Add(role.ToString());

                   

                }

               

                return vals;
            }

     

    Just add a condition where it checks if postedValues has any so change to

       public override IEnumerable<object> ConvertToRecord(Field field, IEnumerable<object> postedValues, HttpContextBase context)
            {
                List<Object> vals = new List<object>();
     
                if (postedValues.Any())
                {
                    var roles = JsonConvert.DeserializeObject<IEnumerable<Role>>(postedValues.First().ToString());
     
                    foreach (var role in roles)
                    {
                        vals.Add(role.ToString());
     
                    }
                }
                return vals;
            }
  • Ben McKean 272 posts 549 karma points
    May 22, 2015 @ 13:37
    Ben McKean
    0

    I've added that code in but getting the same error:

     

    System.NullReferenceException was unhandled by user code

      HResult=-2147467261

      Message=Object reference not set to an instance of an object.

      Source=FormsRepeatableFieldType

      StackTrace:

           at FormsRepeatableFieldType.EducationHistory.ConvertToRecord(Field field, IEnumerable`1 postedValues, HttpContextBase context)

           at Umbraco.Forms.Web.Controllers.UmbracoFormsController.SubmitForm(Form form, FormViewModel model, Dictionary`2 state, ControllerContext context) in f:\TeamCity\buildAgent\work\133677a4e37ceece\Umbraco.Forms.Mvc\Controllers\UmbracoFormsController.cs:line 206

           at Umbraco.Forms.Web.Controllers.UmbracoFormsController.GoForward(Form form, FormViewModel model, Dictionary`2 state) in f:\TeamCity\buildAgent\work\133677a4e37ceece\Umbraco.Forms.Mvc\Controllers\UmbracoFormsController.cs:line 169

           at Umbraco.Forms.Web.Controllers.UmbracoFormsController.HandleForm(FormViewModel model, Boolean captchaIsValid) in f:\TeamCity\buildAgent\work\133677a4e37ceece\Umbraco.Forms.Mvc\Controllers\UmbracoFormsController.cs:line 122

           at lambda_method(Closure , ControllerBase , Object[] )

           at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)

           at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)

           at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)

           at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41()

           at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _)

           at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()

           at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)

           at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33()

           at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49()

      InnerException: 

    My code is:
     
            public override IEnumerable<object> ConvertToRecord(Field field, IEnumerable<object> postedValues, HttpContextBase context)
            {
                var educationHistory = JsonConvert.DeserializeObject<IEnumerable<EducationHistoryItem>>(postedValues.First().ToString());
                List<Object> vals = new List<object>();
     
                if (postedValues.Any())
                {
                    foreach (var educationHistoryItem in educationHistory)
                    {
                        vals.Add(educationHistoryItem.ToString());
                    }
                }
                return vals;
            }
  • Comment author was deleted

    May 22, 2015 @ 13:38

    try changing to(postedValues != null && postedValues.Any())

  • Comment author was deleted

    May 22, 2015 @ 13:40

    ow I see the error 

    this line

    var educationHistory =JsonConvert.DeserializeObject<IEnumerable<EducationHistoryItem>>(postedValues.First().ToString());

    needs to be in the if

  • Ben McKean 272 posts 549 karma points
    May 22, 2015 @ 13:46
    Ben McKean
    0

    Think its fixed now. It was what you said and also needed 

    if (educationHistory != null)

    check before the foreach.

    I've upgraded to the latest version of Forms today and the remove row functionality for the frontend form has now stopped working - do you know any reason why this would start happening?

    Thanks

  • Comment author was deleted

    May 22, 2015 @ 13:47

    Nope see no reason why the upgrade would make that stop... the remove looks for the closest tr, are you still outputting the items in a tr ?

  • Ben McKean 272 posts 549 karma points
    May 22, 2015 @ 13:52
    Ben McKean
    0

    Ok, I've just debugged the JS and think I need to fix a couple of things, so my bad. I needed to add to the JS code to also remove and removed elements from the JSON. JavaScript isn't my strong point but it works if there is a value, its breaking when there isn't so I need to handle that.

    I'll post solution once I've done it

  • Ben McKean 272 posts 549 karma points
    May 22, 2015 @ 13:56
    Ben McKean
    0

    Fixed it now. Remove function ended up like this

     

            $(wrapper).on("click", ".remove_field", function (e) { //user click on remove row from view and element from JSON
                e.preventDefault();
                var rowIndex = $(this).closest('tr')[0].sectionRowIndex - 1; // row index starts at 1, JS index starts at 0
                if ($("#@Model.Id").val() !== "")
                {
                    var jsonString = $.parseJSON($("#@Model.Id").val());
                    // remove this element from JSON
                    jsonString.splice(rowIndex, 1);
                    // repopulate hidden field now we've removed element from JSON
                    $("#@Model.Id").val(JSON.stringify(jsonString));
                }
                $(this).closest('tr').remove();
            })
  • Comment author was deleted

    May 22, 2015 @ 14:06

    Yeah it was just a prototype so can use some fine tuning :) glad that it's all working now!

Please Sign in or register to post replies

Write your reply to:

Draft