Unable to rerender in visualforce Component

AssignTo, as the name suggests, only assigns a value (it's write-only). So, each time the page refreshes, the parent's controller value will reassert itself.

You need to establish a two-way communication channel between the page's controller and the component controller. Here's one way you can do that:

public class component_test_cls {
    public component_test_cls getSelf() {
        return this;
    }
    public component_test_cls() {
        firstParam = 'hello world';
    }
    public String firstParam { get; set; }
}

Which changes your component controller.

public with sharing class Component_cls {
    public component_test_cls parent { get; set; }
    public controllerValue { get { return parent.firstParam; } 
                             set { parent.firstParam = value; } }    
    public void cmdAction() {
        controllerValue = controllerValue.toUpperCase();  
        system.debug('controllerValue '+ controllerValue);
    }
}

Finally, of course, you need to change the assignment in controller and page.

Component

<apex:attribute name="first" type="component_test_cls" description="Descp" required="true" assignTo="{!parent}" />

Page

<c:testCompnent first="{!self}" />

NOTE: Do not assign "name" the same value as the variable name, or Bad Things may happen (this is actually prohibited in later API versions).


The reason why all this goes down has to do with how variables are handled in Apex Code/Visualforce. When you pass a value from one location to another, you actually pass a reference to the variable, not literally the value itself.

So, let's analyze the original situation of your code. First, in component_test_cls, you presumably set a value. In memory, something like this happens:

firstParam = 'hello world';

// Heap Address       Heap Value
// 1234               "hello world"

// Local Variable      Refers To
// firstParam          1234

Next, when assignTo passes the value to your component:

public class Component_cls {
    public String controllerValue { get; set; }
    // assignTo is invoked automatically
    // Local Variable   Refers To
    // controllerValue  1234
}

So, "hello world" is referenced in two places, in component_test_cls and Component_cls.

However, once your action method runs:

public void cmdAction() {
    controllerValue = controllerValue.toUpperCase();
    // Heap Address       Heap Value
    // 1234               "hello world"
    // 2345               "HELLO WORLD"

    // Local Variable                 Refers To
    // component_test_cls.firstParam  1234
    // Component_cls.controllerValue  2345
}

Later, assignTo is run again, and resets controllerValue back to "reference 1234." This means that your work is essentially overwritten.

With the modified version, the primary reference links the parent controller to the child controller, so we can freely modify the variables. Let's look at this:

public class component_test_cls {
    public component_test_cls() {
        firstParam = 'hello world';
        // Heap Address      Value
        // 2345              'hello world'

        // Local Variable    Refers To
        // firstParam        2345
    }
    public component_test_cls getSelf() {
        return this;
        // Heap Address      Value
        // 1234              component_test_cls(1)
        // 2345              'hello world'

        // Local Variable    Refers To
        // firstParam        2345
    }
}

So, we now have a place we can store the reference:

public void cmdAction() {
    controllerValue = controllerValue.toUpperCase();
    // Heap Address       Heap Value
    // 1234               component_test_cls(1)
    // 2345               "hello world"
    // 3456               "HELLO WORLD"

    // Local Variable                 Refers To
    // component_cls.parent           1234
    // component_test_cls.firstParam  3456

    // We use a custom getter/setter, so it effectively references
    // another variable
    // Component_cls.controllerValue  component_test_cls.firstParam
}

After this method returns, assignTo performs its duty and applies "reference 1234" to "component_cls.parent", which it already was, and "reference 2345" has no references left, and is therefore garbage collected (removed from heap/view state).

So, the moral of the story is that if you need to assign a value once, you must either establish parent-child communication, or use a different backing variable.

As an alternative, you could use a write-once assignment:

public with sharing class Component_cls {
    Boolean firstWrite = false;
    public void setFirstValue(String value) {
        if(firstWrite) {
            firstWrite = true;
            controllerValue = value;
        }
    }
    public void cmdAction() {
        controllerValue = controllerValue.toUpperCase();  
        system.debug('controllerValue '+controllerValue);         
    }
    public String controllerValue{get;set;}
}

This performs a once-only write, so you'd adjust your component attribute.

<apex:attribute name="first" type="String" description="Descp" required="true" assignTo="{!firstValue}" />

As you can see, though, if you have many values you want to set, using a wrapper or the parent controller class is more efficient, and allows you to communicate back up to the page controller, or even between different components that need to communicate to each other.

Finally, you could also use just a generic wrapper object so that you can pass references around.