Refresh parent window from child window – conditional reloading with javascript and AJAX

If you work with popups, there will be situations where you need the parent window to update based on some changes/submitted values in the popup window. I will show a solution that is done for myfaces/jsf, and it’s based on the ‘onload’ event of the popup window. I also use ajax (a4j implementation) to update the parent window to avoid a submit and full screen refresh there.

The basic conceptual thoughts about this are quite easy: When you submit a form – or do other actions in your popup that sends data to the server, you need to update the parent window. It could be that you in the popup for example added an item to a table that are displayed in your parent window. So, when you click your button or link in the popup that fires of an action or submit of some sort, you also trigger a javascript on the onclick event that retrieves a hidden button in your parent window and cliks it. This would cause a submit /refresh on you parent window, and the new data that you added from the popup is diplsayed.

Popup.jsp: The popup form with submit button and onclick event:


<h:form id="myPopupForm">
                <t:commandButton id="mySubmit" action="#{myHandler.myAction}" onclick="updateParentWindow();" value="#{messages.myMessage}" >
                </t:commandButton>
</h:form>

Parent.jsp: The parent window hidden button that submits the form or in other ways (onclick event) refreshes that page

<h:form id="updateParentForm" >
        <t:commandButton style="display: none; visibility: hidden;" id="updateParentButton" action="#{myHandler.myAction}"></t:commandButton>
 </h:form>

The script that finds the parent button and clicks it

function updateParentWindow()
{
    var elementToGet = "updateParentForm"+ ":" + "updateParentButton";

    var form = document.forms['updateParentForm'];

    var button = form.elements[elementToGet];

    button.click();
}

But then, if we do it like this – what are the guarantee that the action we fired off in the popup is finished before the parent view is refreshed? None. If we do a submit in the popup, that page will reload. During reloading there is an onload-event that is called, and the popup is not reloaded until the action we fired off has finished. In other words, putting the function inside the onload-event is safe, it will never refresh the parent window before the submit you did is completed. So, let’s move the call of the updateParentWindow()-function from the button to the onload-event of the popup-page:Popup.jsp

<f:verbatim>
    <body onload="updateParentWindow();">
</f:verbatim>

If you now try your application you should se that if you submit the popup, as soon as it has reloaded, your parent window will refresh as well. Nice! This is one big step in the right direction. But there are still some issues to deal with. If I open my popup-window for the first time, I don’t want my parent window to refresh, cause I haven’t done any changes to the data in my popup yet. Having the updateParentWindow() call in the onload event as it is in the example abowe would cause the parent window to be refreshed also the first time the window opens.We want to avoid this, therefore we add some knowledge that the onload event should only trigger the function if the popup page was reloaded by some clicks/submit in the popup-page itself. What we do is to add a boolean value in javascript somewhere inside the body (not the head) of the parent page. It defaults to false, but the links/buttons in the popup will call a small function that set’s this property to true. Then we do a conditional test in the onload event, and only continue if this value is true.The javascript boolean inside the body of the parent page:Parent.jsp

<f:verbatim>
    <script type="text/javascript">
        var fromPopup = false;
    </script>
</f:verbatim>

Our links and buttons in the popup will on the onclick-event set this property to true:Popup.jsp


<h:commandLink onclick="window.opener.fromPopup = true;" action="#{myHandler.myAction}">
        <h:outputText value="myAction"></h:outputText>
</h:commandLink>

And then the conditional reloading would be like this:


<f:verbatim>
    <body onload="if(window.opener.fromPopup)updateParentWindow(); window.opener.fromLink = false;">
</f:verbatim>

It is important to notice that we have to reset the boolean window.opener.fromLink whenever the popup reloads, but we need to do it AFTER the test.

If you are pleased by this solution, no further steps are necessary! But in my application I display a lot of data at the same time, and what I updated in my popup is only a small part of the view in the parent window. Therefore I only wanted to refresh that part of the page, not do a full refresh/reload of my parent window.To do this I use the a4j:commandButton, which has ajax-capabilities and gives me the possibility of rerendering only a part of the page. If you remember we had a hidden button in our parent window that when clicked was responsible for refreshing that page. We modify it a bit, and create an a4j:commandButton instead, and add the reRender property to update the view:Parent.jsp

<a4j:form id="updateParentForm" >
		<a4j:commandButton style="display: none;" id="updateParentButton"  reRender="myComponentOutsideAForm" ></a4j:commandButton>
</a4j:form>

Notice that the area/component I decide to rerender is given by it’s id. Rerendering a component inside a form will fail in Firefox, you will get an error message in the console saying “f has no properties,” and all cliks on links from this point would not work. So either you would have to go for the ordinary submit/refresh, or you can only update areas of the page that doesn’t contain forms. So, applying this code, if you now trigger your submit in the popup page you will se that when it reloads it updates the parent window, but only the part you specified in the ajax-function we created. Avoiding a full refresh gives a better user experience as well as it saves you from retrieving data from the server more than necessary.

Then, what about form validation? Whether you use application validation (business-logic validation in your action methods), or you use the builtin jsf conversion/validation options, or both, it should be possible to handle this as well. If we click a link or button, but the validation fails, we don’t want to update the parent window. This can be done by adding a boolean on the top of our popup.jsp, as well as using this boolean in our updateParentWindow function. Whenever we do an action from the popup, this boolean must be set. If it is business logic validation, it would be easy to set a property if not all requirements are met. If you use the builtin conversion/validation in jsf, you can use the FacesContext.getMessages() to do this. In the popup.jsp, everytime it loads, we get the boolean from our backing bean and pass it on to the javascript. This would avoid the parentWindow to be updated if validation fails.

First, modify the script we use to update parent to respect a boolean parameter:

function updateParentWindow(validationFailed)
{
    if(validationFailed)
	return;
    else
   {
    var elementToGet = "updateParentForm"+ ":" + "updateParentButton";

    var form = document.forms['updateParentForm'];

    var button = form.elements[elementToGet];

    button.click();
   }
}

In the handler we need a boolean property that we can set depending on whether the validation failed or not. We create a private method that will help us to set this boolean, the important thing is that we call it from all our action methods. So the handler might look something like this:

public class MyHandler
{
    private boolean validationFailed = false;

    //Action
    public void doSomething()
    {
        ...
        Some code/business logic
        ...

        If some business logic/validation is not correct, pass this on to the validation method
            setValidation(true);
        If business logic/validation is correct
            setValidation(false);

    }

    private void setValidation(boolean applicationValidationFailed)
    {
        FacesContext context = FacesContext.getCurrentInstance();
        Iterator<FacesMessage> messages = context.getMessages();
        if(messages.hasNext() || applicationValidationFailed)
            setValidationFailed(true);
        else
            setValidationFailed(false);
    }
}

Then on top of our popup jsp inside <% %> tags we retrieve the handler, and we store the boolean property inside a local variable:

<%

MyHandler myHandler = (MyHandler)FacesContext.getCurrentInstance().getApplication ().
getVariableResolver().resolveVariable(FacesContext.getCurrentInstance(),"myHandler");
boolean validationFailed = myHandler.isValidationFailed();
%>

And then we also modify the onload of this page to pass the boolean to the javascript:


<f:verbatim>
    <body onload="if(window.opener.fromPopup)updateParentWindow(<%= validationFailed %>); window.opener.fromLink = false;">
</f:verbatim>

Done! Your popup-page should also respect the validation now, and not update the parent if it fails.

I hope that this example will be helpful, and if not completely adaptable to your requirements it might lead you into the right path. I end this post by showing the popup.jsp and the parent.jsp in whole, to make it easier for you to see what I’ve tried to explain:Parent.jsp

<f:view  >
    <t:document>
    <t:documentHead>
    ...
    </t:documentHead>

    <f:verbatim>
    <body>
    </f:verbatim>

  <f:verbatim>
    <script type="text/javascript">
    //Used in popup
    var fromLink = false;
    </script>
    </f:verbatim>            

    Some content
    ...

    ...

    <h:panelGrid id="myComponentOutsideAForm">
        THIS AREA/CONTENT WILL BE REFRESHED
    </h:panelGrid>

    <a4j:form id="updateParentForm" >
        <a4j:commandButton style="display: none;" id="updateParentButton"  reRender="myComponentOutsideAForm" ></a4j:commandButton>
   </a4j:form>  

<f:verbatim>
    </body>
</f:verbatim>

</t:document>

</f:view>

Popup.jsp

<f:view  >
    <t:document>
    <t:documentHead>
    ...
    </t:documentHead>
<%

MyHandler myHandler = (MyHandler)FacesContext.getCurrentInstance().getApplication ().
getVariableResolver().resolveVariable(FacesContext.getCurrentInstance(),"myHandler");
boolean validationFailed = myHandler.isValidationFailed();
%>
<f:verbatim>
<body onload="if(window.opener.fromPopup)updateParentWindow(<%= validationFailed %>); window.opener.fromLink = false;">

</f:verbatim>

    Some content
    ....

    ....

   <h:commandLink onclick="window.opener.fromPopup = true;" action="#{myHandler.myAction}">
    <h:outputText value="myAction"></h:outputText>
   </h:commandLink>  

<f:verbatim>
</body>
</f:verbatim>

</t:document>
</f:view>

Advertisements

24 Responses to “Refresh parent window from child window – conditional reloading with javascript and AJAX”

  1. Belal Says:

    Hi,
    This seems not simple
    You should have included a complete code at the bottom.
    thank you

  2. roneiv Says:

    Belal,

    sorry to hear you got confused of my explanations. 🙂

    I’ve addded a more complete code of the two pages at the bottom now. 🙂

    Thank you for your interest in my post!

  3. Andreina Says:

    Hi, I hope you could give me a hand…

    I’m trying to update a parent window as a result of some changes that i’ve introduced thru my popup; basically i’m calling my popup so i can introduce data in my DB and when I click the save (button) I want that my parent page shows that data that i just submitted from my popup but without erase all the other data i’ve alredy written in my parent page

    I’ve been trying to do this in a lot of different ways but i’m not getting the result that i want, if you could point me a way to do this it would be great!!

    PD: i’m from a non-speaking english country so i hope that what i have written before make sense…

    Thanks in advance

  4. roneiv Says:

    Andreina, it is a bit hard to try to help you without knowing a bit more 🙂 Do you use a web development framework of any sort (jsf, struts, e.g), or do you simply base yourself on html and javascript or? 🙂

    And when you say that you don’t want to “erase all the other data i’ve alredy written in my parent page,” is this a form with input controls which has not been submitted yet for example?

  5. Andreina Says:

    Actually i’m using JSF, and about your second doubt that’s correct, it’s a form input that hasn’t been submitted yet…

    I could really use an idea, because i’m new with all these technologies and it has been kind of hard…

    If you could point me in the correct way it would be great

  6. roneiv Says:

    Andreina,

    I believe this should be possible by the help of ajax. 🙂 If you have a look at my example where I use the a4j:commandButton, it might help you to understand the capabilities that are there.

    The a4j:commandButton behaves like and ordinary h:commandButton, but it also has a “reRender” property which you can set to an id of a component on you page. This means that when the action/command has finished, it reRenders the component that has the id you used in the reRender property.

    So if you on you parent page have a panelGrid with id “databaseRecords”: whenever you add/save a new record in your popup, in the onclick property of that link/button you execute the “updateParentWindow()” function. This function locates the a4j:commandButton on your parent page, and pushes it. This again causes the panelGrid containing the database records to be reRenderer/updated, and you should see the new record you added. The whole page will not be resubmitted.

    The a4j-components are not part of default JSF (sun spec. or myfaces impl), but you need to get a library called Richfaces, which you can get from here:
    http://labs.jboss.com/jbossrichfaces/downloads/

    Hope this helps you!

    Regards,

    Eivind

  7. Andreina Says:

    Hey thanks for the help, i’m gonna try it and then i’ll tell you how was it

  8. Aamir Says:

    dear it is not working…………favor something good
    thanks.

  9. roneiv Says:

    Aamir,

    I didn’t really understand your comment.

    You can’t get i t working, is it?

  10. Mauricio Says:

    Well done!

    I’m using the solution without ajax and it helped me a lot. 🙂

    I just think that it could be done an improvement: when the popup is submited, the parent window is always reloaded, right? But I think the parent window shouldn’t be reloaded when occurs conversion or validation errors.

    Unfortunately I have no idea how to do this. 😦

    Greetings from Brazil and thanks anyway,
    Mauricio

  11. roneiv Says:

    Mauricio,

    Thank you for your comment! 🙂

    But when it comes to the problem of avoiding reloads of parent window for example with validation errors, this should already be solved by the if test in the onload of the popup page. It is ONLY if a link from within the popup was pressed that the parent window should be refreshed, in all other cases the parent window should not be refreshed. The line:

    #

    should make your application to behave like that. It means that if the window.opener.fromLink is equal to true, submit the function updateParentWindow() that refreshes the parent page. And when the popup loads, the fromLink is reset to false, ready to “register” new clicks.

    When you click a link, the onclick property (which is set like this:
    onclick=”window.opener.fromLink= true;” ) will set the boolean to true, and the parent will be refreshed.

    But if the fromLink is false, which it should be in all other cases, the parent window should not refresh. 🙂

    Hope this explanation helps you!

  12. roneiv Says:

    Sorry my copy and paste of the line that handles if parent window is refreshed was probably not acceppted by wordpress, but here it is:

    ‘onload=”if(window.opener.fromLink)updateParentWindow();window.opener.fromLink = false;”‘

  13. Mauricio Says:

    Roneiv,

    I think we’re having a misunderstanding here. 🙂

    In the example above, the parent window is being always updated when the popup window is submited. Do you agree with me about that?

    Ok then, the problem I tried to expain you is when de popup window submits the data and occurs a conversion/validation errors on server side (note: it’s not Javascript validation).

    Thanks again,
    Mauricio

  14. roneiv Says:

    Hi again Mauricio,

    Yes I agree that whenever you press a link or button in the popup window and window.opener.fromLink is set to true, the parent window will always be updated. But if window.opener.fromLink is set to false, the parent window would not refresh even if popup is submitted. Do we agree on that? 🙂

    But anyway, I understand that you would like to not refresh the parent window if server side validation fails. I’ve extended my example to also include something that I believe would work to handle this case. Please have a look and give me your comments. 🙂

    Regards,

    Eivind

  15. gopal Says:

    hi, in jsp i need to aviod page refreshing,when i click one button it redirect to another page. when i close the opened window after doing some modification in that then previous page will be opened ,there i need the same page values with out refreshing the parent window.

  16. wat Says:

    hi, i am new in c#, can u explain with complete program and output. because i relly want to learn this program…thank you a lot.

  17. Mohammed Yasin Says:

    hi roneiv,
    i developed code for this concept and it is working fine in IE but not working in firefox —
    problem concept:-
    i want to submit the parent window from the child window. the following code works fine in IE but not in firefox
    window.opener.jblst.submit() – jblst denots the parent form name

    thnx for yr timely help
    yasin md.

  18. roneiv Says:

    Mohammed,

    You didn’t say anything about what problems you get in FF, but I guess your problem is that the “form” object you try to submit is empty/null.

    Try using this code instead:

    var myForm = window.opener.document.forms[‘nameOfForm’];
    myForm.submit();

    Regards,

    Eivind

  19. sky Says:

    If the popup refresh for some purposes, the window.opener will lost, and this great example will not work. For example, by using myfaces tag: to do sorting in popup window. Any good idea for this? Thanks!!

    • roneiv Says:

      Sky,

      I haven’t experienced that the window.opener is lost when/if the popup is refreshed. I mean, submitting the popup is a refresh of it, but still the window.opener should be there.

      I don’t know if you could check the window.parent property then to see if there is any reference to it there?

      – E –

  20. guru Says:

    hii i am using jsf2.0 i have created 2 jsf pages using one page i opened another page in a new window and i am changing values in a bean using another window but i need to update changes in first window before clossing second window. i am getting struggled here please someone help me…


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: