2

We have a very large, complex Visualforce page with a very large, complex extension. We have been asked to convert a portion of the functionality to Lightning (using Lightning Out on the VF page). Is there any way we can still continue to use the extension with our Lightning component? Some methods are static, some not. The issue is that the portion we are to convert is not an isolated set of code, but there is a lot of code that would apply to the other functionality on the VF Page as well as the new Lightning component. Due to ongoing updates, keeping the logic in sync between the common code in VF and Lightning would be a major task. Probably cannot be done, but I thought I'd ask.

  • 2
    you should be able to re-use the logic but the methods need to be restructured for the ones getting called from lightning component as static and annotated with @auraenabled – codeyinthecloud Dec 23 '18 at 2:25
  • backup with version control and let the refactoring begin! – Tyler Zika Dec 23 '18 at 2:30
6

Conversion is mostly about changing things around. If you're committed to the effort, it can be done. The degree of difficulty will largely depend on the complexity of the original controller. Well-designed controllers should lend themselves to conversion easily, while less well-groomed code could end up being a nightmare.

Step 0: Organize Your Code

If your code has stuff strewn all over the place consider organizing it before you start. This will greatly ease your effort. You can choose a style that makes sense to you, but here's my "rules" for organizing code.

First, I organize the code in the following order: interfaces, classes, static variables, static blocks, member variables, constructors, and methods. Within each category, I generally order them in order of global, public, protected, and private.

Specific to variables, I prefer to organize final from non-final, and I prefer to clump variables of the same data type together. Specific to methods, I also generally place static methods before instance methods.

You don't need to do this, but doing so will greatly assist you in the next step, which is creating a state wrapper. You can also choose whichever style you prefer, but the better the code is organized so you can find what you're looking for, the faster things will go.

I also tend to leave a generous helping of blank lines to help scanning between content changes. For example, when I have a long list of public variables, and I move on to private variables, I'll leave a blank line between. Over the years, I've found this greatly aids scanning for specific lines.

Step 1: Isolate State

You would want to put most/all of the page state into a state class. This class should not include any static variables, which are already accessible. This allows you to reuse the logic from your non-static methods. Make sure all elements within are @AuraEnabled public. You may need to write additional getters/setters to avoid upsetting the state of your page, though. For most controllers, this would be the most amount of work.


Classic Visualforce State

public class vfController {
    public String string1 { get; set; }
    public String string2 { get; set; }
    public Boolean boolean3 { get; set; }
    ...

Wrapped Visualforce State

public class vfController {
    public class pageState {
        @AuraEnabled public String string1 { get; set; }
        @AuraEnabled public String string2 { get; set; }
        @AuraEnabled public Boolean boolean3 { get; set; }
        ...
    }
    public pageState state { get; set; }
    public vfController(...) {
      state = new pageState();
      ...
    }
    ...
}

Accessing The New State

You have two choices make things behave the the way you used to.

Option 1: Adding getters/setters

public String string1 { get { return state.string1; } set { state.string1 = value; } }
public String string2 { get { return state.string2; } set { state.string2 = value; } }
public String boolean3 { get { return state.boolean3; } set { state.boolean3 = value; } }
...

Option 2: Modifying The Page

You can basically just wire the merge fields to the new state.

<!-- old style -->
... value="{!string1}" ...
<!-- new style -->
... value="{!state.string1}" ...

Step 2: Converting Non-Static Methods

Add a new version of the method that is static, returns the page state, and accepts the page state. Have the new method be called by the old.

Example

// original VF method
public void doSomething() {
  doSomethingLC(this.state);
}
// And now for Lightning
@AuraEnabled public state doSomethingLC(state input) {
  // do something with input
  return state;
}

Step 3: Converting Static Methods

Add @AuraEnabled, make public.

Step 4: Gotchas

Extensions, component controllers, utility classes, etc might all need special consideration. Not all code is created equal. Some classes may be trivial to modify, others might be a nightmare. It all depends on what the class is doing and how its structured.

Developers that have been writing lean, clean code for a while should find the process fairly effortless, but there's a lot of bad code out there that might be very hard to salvage, in which case you can write a new controller following the patterns above, and drop it in as a replacement for the original the next time you update the VF page.

And, of course, don't bother converting methods that won't be used, because you aren't gonna need it.


Alternative To Steps 2 And 3

Instead of putting the new LC methods in the same class, put them in a new controller class; they're already static, so you can call them by name. This will make the Lightning Controller a lot easier to read, since it is likely you'll end up moving everything to Lightning anyways, and you won't have to strip out all the old Visualforce code in the process.

| improve this answer | |
3

Is there any way we can still continue to use the extension with our Lightning component?

Sure you can. But as you realized you will need to have static methods and that you will need to annotate the methods with @AuraEnabled.

But conversions are not as easy as thought. Because the time you convert a VF controller method to that required by aura components, the former will stop working.

With little refactoring along with a modular approach you can utilize the common code between your VF and Component. And not to be forgotten one of the important things, regression testing.

Let’s say you have a controller method as below:

public PageReference myVFMethod() {

     /*
      * common code
      */

    return pageRef;
}

where the common code exists that will be utilized in your aura component as well. You can then refactor this as:

public PageReference myVFMethod() {
    ...
    myCommonMethod();
    ...
    return pageRef;
}

@AuraEnabled
public static <return type> myAuraMethod() {
    ...
    myCommonMethod();
    ...
}

private static <return type> myCommonMethod() {
    ...
}

This way you will not need to change anything on your VF and you can still create new methods for your Aura components.

While this is an example of how you can reuse the common code either using new methods or say moving the logic to another helper class or so, but on top of this what you will need is a regression testing. With any such change make sure you test this out to capture any bug that may have been introduced.

In summary, there is always a way to utilize classes for different purposes but it depends on complexity and reusability if you want to continue using same class or create separate classes.

| improve this answer | |
  • ViewState and bindVariables in the controller are a big pain in this. Most of the time, I feel rewriting code from scratch would be better and efficient than converting it. – Pranay Jaiswal Dec 23 '18 at 5:16
  • True. While there can be scope to reutilize code but there are lot other considerations. – Jayant Das Dec 23 '18 at 15:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.