Wednesday, December 28, 2011

easy double-click to edit related-list VF page

Often enough I am asked to make a custom VisualForce of a related list that is editable in a similar way to salesforce's native double click to edit. I have made them in a variety of ways, including adding images like salesforce's to indicate if a field is editable or locked etc. and some simpler ways like the one I am going to do now.

The Problem:
a sObject under Account(or any other obj) needs show on the Account page layout, but it also needs to be double-click to edit to make it easy for the reps to update key information on the fly without having to click into each sObject. (for this example we will use the Contact obj)


Setup:
First we need to create a controller extension so that it can sit in the page layout of the Account obj, and even though we are showing the contact obj, the extension needs to point to account otherwise it wont show up as an available VisualForce page to add on the layout.
ContactInLineEdit.cls
ContactInLineEdit.page

This is a standard controller extension setup, this allows the class to use the account id referenced in the URL when the page is accessed. Example page URL will be 'apex/ContactInLineEdit?id={!account.id}'

Now we should add the Contact list to the class so we can access it on the page in a apex:repeat, when we add it to the class, we only need to get the list on load of the page, and then again when we update the fields.
ContactInLineEdit.cls

On the page we will need to add the apex:form tag, along with an apex:outputpanel with an id so we can call it later in a rerender attribute on the update call. We will also add the CSS and jQuery files that will help us control the double-click to edit functionality. We then place the jQuery inside the outputpanel so when it rerenders it can reapply the jQuery to the page. I also prefer to use the jQuery.noConflict(); since I often run into issues with salesforce's JS conflicting with what I am trying to implement.
ContactInLineEdit.page

Now we need to add the apex:pagemessages so we can do error handling and we need to add the table for the apex:repeat to sit in. We will also add the apex:outputfiled's that will display in the related list on the page, we need to make sure that any field we reference here is also in the select query on the class.
ContactInLineEdit.page

Lets add in the loading icon for the update and a JS function to control it, and we should also add the edit fields to the table. To help control the conditional hiding and showing of the fields for the edit, we should add some div's with classes to reference in jQuery.
ContactInLineEdit.page
ContactInLineEdit.page

Lets add the double click functionality, first we need to add a class to the edit text in the action column  <span class="editLink">Edit</span> then we need to add a function so that everytime the nonEdit field (outputField) is double-clicked it will hide the outputField and show the inputField. We will also change the Edit text to Cancel and add a class to it so we know that row is in edit mode.

Now lets add the edit row/cancel row edits functionality, this will allow all editable fields in the row to be edited and if cancel is hit, it will undo all edits by retrieving the text from the hidden outputfield otherwise it will continue to show the updated text since we are just hiding and showing. We don't want to clear the fields cause that will potentially clear out the saved info if it gets saved by mistake. So by retrieving the info from the outputfield, we are able to set it back to what it was originally.
ContactInLineEdit.page

We will also need to update our edit action to use the new function, it will now look like this: <span class="editLink" onclick="EditMe(jQuery(this));">Edit</span>
At this point we need to make the update method and add it to the page, this will allow any edits made by the user to be saved, and then the list will rerender with the new information.
ContactInLineEdit.cls

ContactInLineEdit.page

And that it, simple. I didn't add it here, but field validation could be added to ensure its a proper email or phone number etc. In the style i made so that fields that were editable when the mouse hovered over it, the cursor would change to a pointer like it would when the mouse hovers over a link. This way the user knows the field is editable instead of having to add an image that could bog down the page load.

Questions?  
Twitter: @SalesForceGirl  or Facebook

32 comments:

  1. Thanks for sharing this - very useful

    ReplyDelete
  2. This is great!!! Could you share the source as downloadable files for easy copy/pasting?

    ReplyDelete
  3. Thanks for this useful hint! Some screenshots or a short screencast would be very helpful.

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. I am a bit new to Apex development, so at this point I am just copying the code and modifying to match my needs.
    Can someone expand a bit or provide an example of the CSS file that is needed for this to work?

    Thanks in advance.

    ReplyDelete
    Replies
    1. the hideIt class is {visibility: hidden;} and the hideMe class is {display:none;} other than that its all standard style.

      let me know if you need more...

      Delete
    2. Randi,
      I've gone over every bit of code from the above images multiple times, tried different versions of the jquery file and just can't seem to get this to work. It gives the table on the record page but it is not editable. What might I be doing wrong? Here is a screenshot of what it looks like if that helps.
      Thanks,
      Amanda
      http://picpaste.com/InlineEditRelatedListVF-SLCL05zM.JPG

      Delete
  6. Thank you for the quick response.
    I was actually able to figure that out from one of her other posts with samples...

    Been a while since I did html/css/javascript so everything is coming back as I play with it!

    ReplyDelete
  7. Is it possobile to replace Related list with VF Page?

    ReplyDelete
  8. I am trying to use this with a custom object related list on opportunities. I've essentially been changing the account mentions from the code to opportunity and the contact mentions to my custom object Course__c. However I am running into an issue with the ContactInLineRes lines because I am getting an error of "Error: Static Resource named CourseInLineRes does not exist. Check spelling". I also tried it with Course__cInLineRes but it still says that it doesn't exist. Can you please tell me what I am doing wrong?

    Thanks,
    Amanda

    ReplyDelete
  9. I'm also receiving this error on the controller:
    Error: Compile Error: Method does not exist or incorrect signature: GloabalHelper.CheckForNotNull(LIST) at line 13 column 12

    ReplyDelete
  10. Amanda -
    You need to create a zip file with the resources that you are trying to use or refer to, and upload it to the DEVELOP > Static Resources section.
    My zip file included the following files:
    jquery-1.7.1.min.js (you can find the file on google)
    loader_24x26.gif
    css.css (with the css code needed for my VF page)

    You also need to create the Global Helper Class to use the method you referenced in the code above.
    Luckily for you SF Girl provided it in another page:
    http://salesforcegirl.blogspot.com/2011/03/global-helper-classes-top-5-methods-to.html

    Hope this helps.

    Ohad

    ReplyDelete
    Replies
    1. Ohad,
      Thanks. I'm not sure what obvious thing I'm missing is but I'm trying to create the Global helper class/classes from the page you mentioned and I also looked at http://salesforcegirl.blogspot.com/2011/03/helper-classes-what-are-they.html but when I just try to copy and paste the code into a new class I get errors for the first line. Is there some basic first step/line that I am just not understanding? I also tried looking up Global Helper classes to see if I could figure it out that way but no luck. If you could help me understand that would be so wonderful.

      Thanks,
      Amanda

      Delete
    2. Amanda,

      What errors are you receiving for the first line?

      Ohad

      Delete
    3. Ohad,
      I created a new class the normal way and copied the check for not null code which starts with

      public static boolean CheckForNotNull(List lstInValueToCheck)

      (after the 6 lines of notes that is)

      I then get the error "Compile Error: unexpected token: 'boolean' at line 7 column 14". If I delete the 6 lines of notes I get the same error just at line 1.
      Thanks,
      Amanda

      Delete
    4. Amanda,

      You should read more about Apex Classes to understand how to define one properly. There is plenty of material online - I myself learned using Google and sites just like this :)
      In the mean time - You cannot start a class by defining only its methods. You must first define the Class itself.

      Your first line should be:
      public with sharing class GlobalHelper {

      and of course, after your method you must close it with another }.

      Hopefully this helps.

      Regards,
      Ohad.

      Delete
    5. Thanks...I think the Holidays turned my brain to mush. I feel like an idiot. I've made test classes and such before...I just assumed that Public static was some special way of starting a helper class or something.
      I'm again getting an error regarding the methods....maybe I'm being an idiot again but I got the first few helper parts (Check for Null value and Get param) in the class and saved without issue but it's giving me an error when I add the Check Value method or any of the helpers after that. It says Compile Error: Method does not exist or incorrect signature: GlobalHelper.CheckForNotNull(LIST) at line 73 column 10 which that line in the code is if(GlobalHelper.CheckForNotNull(lstInValueToCompare))
      I didn't think you could have more than one class with the same name but I tried it anyway just to see if these were supposed to be separated and I still get the same error or a similar.
      My goal for early this year is to go through the developer courses and gain a better understanding of this so I won't feel like such an idiot.
      Thanks so much for your help,
      Amanda

      Delete
    6. You can have a method defined more than once for different types of input params.
      You can have a method that will check for not null on lists, on strings, etc...
      My guess is that you did not create a method for lists, which is the object you are passing to the method.

      Ohad

      Delete
    7. Okay thanks. I was just taking them from that page of Top 5 Methods but I guess they are not fully defined...just kind of a draft for you to flesh out?

      Delete
    8. Take a look at my GlobalHelper Class.
      Hopefully this will help you.

      http://pastebin.com/95y1H87C

      Regards,
      Ohad

      Delete
    9. Thanks Ohad....I now have it not showing errors anymore and can get it in the page layout on the main detail section. Would you mind sending me your css file or posting it in pastebin so I can try to figure out what I need to do there?

      Thanks again for all your help,
      Amanda

      Delete
    10. Here is my CSS

      http://pastebin.com/aveRY4aJ

      Delete
    11. I've got everything showing on the page now but the whole edit hide/show and save functions don't seem to be working. Here's a screenshot - http://picpaste.com/InlineEditRelatedListVF-ARAkNA5G.JPG
      Did you have issues getting this part to work? Was there something extra you had to do that wasn't shown in the code above?

      Thanks,
      Amanda

      Delete
    12. Ohad, Any chance you would be willing to pastebin your visual force page you did with this? I've checked and rechecked the code but since I had to transcribe it all from the images rather than copy and paste I am wondering if maybe there is something in my code that is causing it to not work. I've looked at it in the Salesforce platform and the Force.com IDE and can't see anything wrong but a mispelling or a space where there shouldn't be might be the difference. I could see if copying your code, inserting my custom object works.

      Thanks so much,
      Amanda

      Delete
    13. Amanda,

      Sorry I forgot to do this...
      Here is the pastebin of my vf page.
      Keep in mind it was modified based on my needs...

      http://pastebin.com/PPr2AJj8

      Good luck,
      Ohad

      Delete
    14. Thank you Ohad. I've only found a few lines in your code that are different from what's in the images above but I guess they make all the difference. Now the only issue I'm having is that two of my fields are text fields. One is a standard 255 text field and the other a long text field. Neither of them will allow me to double click but my object name field and two other lookup fields are working perfectly. Any ideas as to why this might be happening on the text fields?

      Thank you so much!
      Amanda

      Delete
    15. Correction, they only don't work to double click if they are blank (which by default when the course is added they are blank). If there is text in there already then they work just fine. Other than putting a default N/A in the field I'm not sure how to correct this.

      Thanks!
      Amanda

      Delete
    16. Ohad,
      Thank you so much for all your help with this. I got it working in the sandbox but now deploying it to production I found out that these classes need testclasses (I naively thought that just triggers had to have test classes). Could you please pastebin your test class for your globalhelper file? I know it won't be exactly the same as mine but it would be close and just trying to test the first controller is proving difficult.

      Thanks again,
      Amanda

      Delete
    17. This conversation has been immensely helpful, I don't think I'd have figured all of this out without it.

      I'm about to the test method phase of all of this. Have you had any luck Amanda?

      Delete
  11. Amanda, Ben,

    I completely missed your comment for help with the test method.
    I wrote the linked test method - though there is probably a much more effective way to do it.
    Hopefully this will give you a good starting point.

    http://pastebin.com/Ca9VTD0N

    Regards,
    Ohad

    ReplyDelete
    Replies
    1. Just wanted to say thanks for helping here @Ohad! :-) you rock!

      Delete
    2. Happy to be of help....
      I've learned most of what I know from places like this and from other people who helped - so this is just passing it forward :)

      Delete