+ Start a Discussion
MellowRenMellowRen 

ActionFunction or JavaScript error...

Trying my hand at Extension Javascript interaction but can't seem to get the Action method to run.

 

Just stripped my page to the bare essence.

 

----------------
Visualforce Page
----------------

<apex:page StandardController="Opportunity" extensions="Opp_Edit_Extension">
    <apex:form id="WholePage">
    
        <!-- ActionFunctions -->
        <apex:actionFunction name="showPageIsTrue" action="{!showMainPageToTrue}" reRender="WholePage"/>

        <script type="text/javascript">
            var isOppApp = (true == true);
            if(!isOppApp) {
                alert('Huh?');
            } else {
                showPageIsTrue();
            }
        </script>

        <apex:actionRegion rendered="{!IF(showMainPage, false, true)}">
            <apex:pageBlock mode="edit" title="Error">
                Don't want to see this.
            </apex:pageBlock>
        </apex:actionRegion>
        
        <apex:actionRegion rendered="{!IF(showMainPage, true, false)}">
            <apex:pageBlock mode="edit" title="Yah!">
                This be good.
            </apex:pageBlock>
         </apex:actionRegion>
    </apex:form>
</apex:page>

----------------
Extension
----------------

public with sharing class Opp_Edit_Extension {
    // Getters & Setters
    public Boolean showMainPage{get; set;}
   
    // Constructor
    public Opp_Edit_Extension(ApexPages.StandardController controller) {
        //set up initial values
        showMainPage = false;
        system.debug(showMainPage);
    }
    
    // Action methods
    public PageReference showMainPageToTrue() {
        showMainPage = true;
        system.debug(showMainPage);
        return null;
    }
}

 

If I run this the page displays the "Don't want to see this." message. If I look at the logs, I can see the "Debug|false" but no "Debug|true" so it appears that either my JavaScript is not calling the ActionFunction or the ActionFunction is not calling the Extension method. 

 

Can anyone tell me what mistake I have made?

 

Regards

MellowRen

Best Answer chosen by Admin (Salesforce Developers) 
sfdcfoxsfdcfox

The function presumably bombs because the form isn't completely rendered when showPageIsTrue is called (the DOM isn't complete). I just wrapped your function in a function, attached it via an onload handler, and went about my merry business (and it worked). Here's the modification I used:

 

<apex:page StandardController="Opportunity" extensions="Opp_Edit_Extension">
    <apex:form id="WholePage">
    
        <!-- ActionFunctions -->
        <apex:actionFunction name="showPageIsTrue" action="{!showMainPageToTrue}" reRender="WholePage"/>

        <script type="text/javascript">
	function init() {
        var isOppApp = (true == true);
        if(!isOppApp) {
            alert('Huh?');
        } else {
            showPageIsTrue();
        }
    }
        if(window.addEventListener)
        	window.addEventListener('load',init,true)
        else
            window.attachEvent('onload',init)
        </script>

        <apex:actionRegion rendered="{!IF(showMainPage, false, true)}">
            <apex:pageBlock mode="edit" title="Error">
                Don't want to see this.
            </apex:pageBlock>
        </apex:actionRegion>
        
        <apex:actionRegion rendered="{!IF(showMainPage, true, false)}">
            <apex:pageBlock mode="edit" title="Yah!">
                This be good.
            </apex:pageBlock>
         </apex:actionRegion>
    </apex:form>
</apex:page>

Note, if your attempt is to call "showMainPageToTrue" before the user can see it, use apex:page's "action" attribute; it will cause the action to be called after the constructor but before the page is serialized and rendered.

All Answers

sfdcfoxsfdcfox

The function presumably bombs because the form isn't completely rendered when showPageIsTrue is called (the DOM isn't complete). I just wrapped your function in a function, attached it via an onload handler, and went about my merry business (and it worked). Here's the modification I used:

 

<apex:page StandardController="Opportunity" extensions="Opp_Edit_Extension">
    <apex:form id="WholePage">
    
        <!-- ActionFunctions -->
        <apex:actionFunction name="showPageIsTrue" action="{!showMainPageToTrue}" reRender="WholePage"/>

        <script type="text/javascript">
	function init() {
        var isOppApp = (true == true);
        if(!isOppApp) {
            alert('Huh?');
        } else {
            showPageIsTrue();
        }
    }
        if(window.addEventListener)
        	window.addEventListener('load',init,true)
        else
            window.attachEvent('onload',init)
        </script>

        <apex:actionRegion rendered="{!IF(showMainPage, false, true)}">
            <apex:pageBlock mode="edit" title="Error">
                Don't want to see this.
            </apex:pageBlock>
        </apex:actionRegion>
        
        <apex:actionRegion rendered="{!IF(showMainPage, true, false)}">
            <apex:pageBlock mode="edit" title="Yah!">
                This be good.
            </apex:pageBlock>
         </apex:actionRegion>
    </apex:form>
</apex:page>

Note, if your attempt is to call "showMainPageToTrue" before the user can see it, use apex:page's "action" attribute; it will cause the action to be called after the constructor but before the page is serialized and rendered.

This was selected as the best answer
souvik9086souvik9086

There must be some javascript error. You can do one thing. Execute the page in Firefox then just check in the Error Console what problem is coming in the javascript.

 

To see error console

 

In firefox

Tools -> WebDeveloper -> ErrorConsole

 

If this post solves your problem kindly mark it as solution. if this post is helpful please throw Kudos.

Thanks

MellowRenMellowRen

sfdcfox

 

That works brilliantly. Thanks for that.

 

 if your attempt is to call "showMainPageToTrue" before the user can see it, use apex:page's "action" attribute

 

To be honest, it is. Unfortunately, the first test in the script, which I rewrote here as "isOppApp = (true == true)", can only be done in Javascript as far as I know. Essentially I am testing what Application the user is running from. May be I went about this all the wrong way. I want a special "Admin" page that has access to a limited number of special fields and some related objects. It is likely to be very static in its design over time unlike our system Opportunity page where we add/move/modify fields all the time—hence I don't really want to maintain a Visualforce page when the standard is fine.

 

My solution.

  1. Override the Opportunity Edit function to call this Visualforce page.
  2. This page checks what Application the user is in and unless it is the Admin one redirects the page to the standard Opportunity Edit page.

This all works fine. Didn't even need an Extension.

 

My problem is that the "default" page is now the Admin one and I asked the question "what happens if someone loads this without JavaScript running?". Even just viewing it will show some things that management wouldn't be pleased about if in the wrong eyes. So I decided to make the default page show a "You must have JavaScript running" error and then use Javascript to flip the render toggle and display the real page. Since only JavaScript can flip the toggle, JavaScript must be running and most people will get redirected as planned. I thought it was a nice/clever idea. First of all I spent a frustrating number of hours trying to do it in VisualForce/Javascript only. Then it occured to me that the finished Admin page is going to require an extension anyway, so I created that and then got stuck again. 

 

Your solution does produce a bit of a flash of the error screen but I don't care (as much) about that if just on the Admin page—so I modified your solution slightly by moving only showPageIsTrue into init() and putting your eventListener code inside the original else statement.

 

Just for my own sanity, would you have done any of the above in a different/easier way?

 

Regards

MellowRen

 

MellowRenMellowRen

Souvik

 

It wasn't in this case but to get here I was using alert()s all over the place to test the Javascript. Thanks for this tip as it will make my life easier in the future.

 

Regards

MellowRen

sfdcfoxsfdcfox
Your description sounds like there could be, or should be, a native, non-coding method to achieve all your dreams for this page. Using multiple page layouts, assigned to the correct profiles, and field level security to prevent access to those "special" fields would be the way to go about the majority of what you're doing.

You shouldn't be depending on JavaScript security to go about your business, because that's simply not secure. For example, the user could use Chrome to intercept a part of the page logic, modify it, then gain access to the restricted information. Granted, that's a power user/developer-type person that probably deserves a raise or a promotion, but the point remains, if there's a client-level security mechanism, it is easily compromised.

There should be a non-Visualforce way to present a basic layout with most information, then you could embed the Visualforce into the layout if you wanted to. A partial layout is far simpler to use than coming up with an elaborate scheme that involves JavaScript checking and so on.

Try it out, and let me know if you get stuck. The community would be glad to help you out. Sometimes the best solution in salesforce.com simply isn't code, and it sounds like this falls in that category.
MellowRenMellowRen

Should be and definately would be my prefered option. May be I went about it wrong from the beginning.

 

I have a requirement that two profiles are allowed to use this 2nd Opportunity Edit page, but both profiles will only want to occasionally, normally they to will need the non-special page. So what I did was create a new Application and put an Opportunities tab in there—I really want the standard Opportunity list with filter views. Applications can be restricted by Profile so I thought this was a good start. When you overide the Edit button though it does so for all Applications—so the Sales Application users get the new page as well. No problem, have an intermediately page whose apex:page action redirects based on which Application the user is in.

 

Except I couldn't. As far as I was able to find (lot's of Googling) the only way to determine what Application you are in is by using Javascript. And the apex:page action can't run Javascript. And that lead me down this garden path. 

 

I'd appreciate a knock on the back of the head and a different starting point but really can't see how to get around the one-profile-double-edit-page thing.

 

MellowRen

 

 

sfdcfoxsfdcfox
There's several convenient ways you could do this.

Here's one thought:

Create two record types; grant the second record type just to the profiles that need it. Assign differing standard page layouts to each. Have the user change the record type from one to the other to get the "special" page layout (e.g. [Change], select new record type, [Continue], edit the fields you want). If you want the record type to revert back to the default after editing, just use a trigger. That reduces your total code needs to about 5 lines of code.

Here's another:

Create a custom button, lay it onto a page layout, and assign that layout to the users that want it. From here, they can simply click on the button to go to your Visualforce page for custom editing. This reduces your total liability to just a single visualforce page that doesn't need any JavaScript "hacks."

Regardless of how you look at it, you should avoid attempting to detect the user's application, for a myriad of reasons, not limited to the fact that the internal page structure can (and may very well) change, breaking your code. This increases maintenance, of course. I'd go with either of the two suggestions I posted here.
MellowRenMellowRen

I will give Option 2 a go and see if I can make it work for me. Thanks for all the help.

 

Regards

MellowRen