Retrieve the fragment (hash) from a URL and inject the values into the bean

13,048

Solution 1

You can do this with help of window.onhashchange which fills an input field of a hidden form which submits itself asynchronously when the input field has changed.

Here's a kickoff example of the Facelets page:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>SO question 3475076</title>
        <script>
            window.onload = window.onhashchange = function() {
                var fragment = document.getElementById("processFragment:fragment");
                fragment.value = window.location.hash;
                fragment.onchange();
            }
        </script>
        <style>.hide { display: none; }</style>
    </h:head>
    <h:body>
        <h:form id="processFragment" class="hide">
            <h:inputText id="fragment" value="#{bean.fragment}">
                <f:ajax event="change" execute="@form" listener="#{bean.processFragment}" render=":showFragment" />
            </h:inputText>
        </h:form>
        <p>Change the fragment in the URL. Either manually or by those links:
            <a href="#foo">foo</a>, <a href="#bar">bar</a>, <a href="#baz">baz</a>
        </p>
        <p>Fragment is currently: <h:outputText id="showFragment" value="#{bean.fragment}" /></p>
    </h:body>
</html>

Here's how the appropriate bean look like:

package com.stackoverflow.q3475076;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.event.AjaxBehaviorEvent;

@ManagedBean
@RequestScoped
public class Bean {

    private String fragment;

    public void processFragment(AjaxBehaviorEvent event) {
        // Do your thing here. This example is just printing to stdout.
        System.out.println("Process fragment: " + fragment);
    }

    public String getFragment() {
        return fragment;
    }

    public void setFragment(String fragment) {
        this.fragment = fragment;
    }

}

That's all.

Note that the onhashchange event is relatively new and not supported by the older browsers. In absence of the browser support (undefinied and so on), you'd like to check window.location.hash at intervals using setInterval() instead. The above code example should at least give a good kickoff. It works at at least FF3.6 and IE8.

Solution 2

Here's the most reliable way to extract a fragment from a syntactically valid URL / URI.

 URI uri = new URI(someString);
 String fragment = uri.getFragment();

How you inject this into a bean will depend on what server-side framework you are using, and whether you are doing the injection using XML or annotations, or doing it programmaticaly.

Solution 3

The fragment cannot be seen from the server-side, it can only be accessed by client-side scripts. The way it's usually done is that the server-side generates a non-parameterized page, which is then modified by scripts in accordance with the fragment parameters. The scripts could make AJAX requests with query parameters, where the AJAX responses are generated by JSF using beans controlled by the parameters.

If you absolutely want the server-side to have access to the fragment parameters when rendering the page itself, you need to reload the page with the parameters as query parameters instead.

EDIT: To reload the page you could use this code:

if (window.location.hash != '') {
  var newsearch = window.location.search;
  if(newsearch != '') {
    newsearch += '&';
  }
  newsearch += window.location.hash.match(/#?(.*)/)[1];
  window.location.hash = '';
  window.location.search = newsearch;
}

Solution 4

Watch this question and especially the answers: JSP Servlet anchor

  • Fragment cannot be seen on server-side.
  • You can extract fragment on client-side, convert it and send to the server via Ajax.
Share:
13,048
Shivender Khajuria
Author by

Shivender Khajuria

Updated on June 03, 2022

Comments

  • Shivender Khajuria
    Shivender Khajuria almost 2 years

    I am looking for a way to inject values from the fragment (#) of a URL into bean(JSF), in the same way query-parameter values are injected. I am using Ben Alman's Bookmarkable jQuery plugin (http://benalman.com/projects/jquery-bbq-plugin/) to create the URL fragments. I was hoping that Custom regex patterns from prettyFaces could be a way to solve my problem but until now I have been unsuccessful.

    (http://ocpsoft.com/docs/prettyfaces/snapshot/en-US/html_single/#config.pathparams.regext)

    I would like to define here my situation and if any one has an idea, i would love to try them out.

    I am using
    RichFaces: 3.3.3,
    Spring: 3.0.2.RELEASE,
    Hibernate: 3.5.3-Final,
    JSF: 2.0.2-FCS,
    PrettyFaces: 3.0.1

    The web application generates, following kind of URL where parameters are listed after a hash(#). The idea is to have an ajax based Bookmarkable URL. So every time I click on an element that changes the state of the system, the value is sent to the server via ajax and the URL after the hash is rewritten. There can be 1 to 3 parameters after the hash, the number of parameters are optional.

    My goal is, when the user bookmarks the URL (with hash) and than revisits the saved page, the page should inject the correct values into the system and visualize the page in the previous state (like query-parameter).

    Below, I have a regular expression that would catch all the parameters after the hash.

    //URL:   
    http://localhost:8080/nymphaea/workspace/#node=b48dd073-145c-4eb6-9ae0-e1d8ba90303c&lod=75e63fcd-f94a-49f5-b0a7-69f34d4e63d7&ln=en
    
    //Regular Expression:    
    \#(\w*\=(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}))|\&(\w*\=(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}))|\&(\w*\=\w{2})
    

    I know there are websites that some how send the URL fragment into there server side logic,

    Is there anyway to inject values from the URL fragments into server side beans?

  • Shivender Khajuria
    Shivender Khajuria almost 14 years
    I saw that technique used by facebook where the fragment parameters are converted to query parameters when the page is reloaded. I would like to try this idea. How can a URL containing fragment be transformed into URL with query params on page reload? i.e. url.com/#a=1&b=2 -> url.com/?a=1&b=2
  • Shivender Khajuria
    Shivender Khajuria almost 14 years
    Thanks for your idea. I am looking for a way to catch the URL when there is a page reload (GET) and than do getFragment(), parse it correctly to get the values and than set the respective variables.
  • pcjuzer
    pcjuzer almost 14 years
    It's okay that the method exists there, but browsers don't send fragment info to the server. It can be seen by logging HTTP traffic.
  • BalusC
    BalusC almost 14 years
    While technically correct, this answer is practically and fundamentally wrong. The fragment set by the webbrowser [ will not ](en.wikipedia.org/wiki/Fragment_identifier#Processing) arrive at the webserver.
  • clacke
    clacke almost 14 years
    Added example code. However, I would suggest that you instead write code to parse the params and make the appropriate AJAX request to reconstruct the bookmarked state. Also, my code example is too simple for your needs, it doesn't check for e.g. duplicated params and will therefore run into problems when the user starts clicking around and you start adding things to the fragment again.
  • clacke
    clacke almost 14 years
    Great reference. Especially the ajaxpatterns link.
  • BalusC
    BalusC almost 14 years
    The code example is clumsy. Just window.location.hash gives you already the fragment and window.location.search the query string. Read the window.location docs.
  • Stephen C
    Stephen C almost 14 years
    Good point. However you can send a URL with a fragment ... if you encode it and send it as a query parameter to a different URL. That's how a lot of annotation and bookmarking tools work.
  • clacke
    clacke almost 14 years
    You read an old version of the example. I already corrected it before you commented.
  • BalusC
    BalusC almost 14 years
    Right, this must have been a too-long-opened browser tab :)
  • clacke
    clacke almost 14 years
    Wow, that is simply awesome, thanks for sharing. Now I need to take a look at JSF 2.
  • BalusC
    BalusC almost 13 years
    For IE6/7 browsers, consider jQuery Hashchange plugin. See also stackoverflow.com/questions/5911899/…