Navigate using p:selectOneMenu

2019-03-21 02:03发布

问题:

I'm using a select one menu to do navigation to different parts of my site:

<p:selectOneMenu value="#{navigator.outcome}">                      
    <f:selectItem itemLabel="Select page..." />
    <f:selectItem itemValue="page1" itemLabel="Page 1" />
    <f:selectItem itemValue="page2" itemLabel="Page 2" />
    <f:selectItem itemValue="page3" itemLabel="Page 3" />
    <p:ajax event="change" listener="#{navigator.navigate}" />
</p:selectOneMenu>

Is there a more SEO friendly way of doing this? I'm worried that the JavaScript links won't get followed.

回答1:

Use custom content with <p:column> with therein a <h:link>.

Bean:

private List<Page> pages;

@PostConstruct
public void init() {
    pages = new ArrayList<Page>();
    pages.add(new Page("Page 1", "/page1.xhtml"));
    pages.add(new Page("Page 2", "/page2.xhtml"));
    pages.add(new Page("Page 3", "/page3.xhtml"));
}

View:

<p:selectOneMenu var="page">
    <f:selectItems value="#{bean.pages}" var="page" itemLabel="#{page.title}" />
    <p:column>
        <h:link value="#{page.title}" outcome="#{page.viewId}" />
    </p:column>
</p:selectOneMenu>

Note that this doesn't work with List<SelectItem> nor individual <f:selectItem> entries. You really need to provide a List<Entity> (wherein Entity is Page in the above example).

This generates a <table> with fullworthy and crawlable (and clickable!) <a> elements.

See also:

  • What is the difference between redirect and navigation/forward and when to use what?
  • How to navigate in JSF? How to make URL reflect current page (and not previous one)


回答2:

just create function navigate as :

<p:selectOneMenu value="#{navigator.outcome}">                      
    <f:selectItem itemLabel="Select page..." />
    <f:selectItem itemValue="page1" itemLabel="Page 1" />
    <f:selectItem itemValue="page2" itemLabel="Page 2" />
    <f:selectItem itemValue="page3" itemLabel="Page 3" />
    <p:ajax event="change" listener="#{navigator.navigate}" />
</p:selectOneMenu>

public void navigate() {
    FacesContext context = FacesContext.getCurrentInstance();
    NavigationHandler navigationHandler = context.getApplication()
            .getNavigationHandler();
    navigationHandler.handleNavigation(context, null, outcome
            + "?faces-redirect=true");
}


回答3:

There are many ways to ahieve what you want. First of all, I will describe alternatives to your approach and then will post some remarks on SEO.

Using a normal form submit on change event

First of all, you could handle your navigation via a normal form submit, when user implicitly submits a form on a change event:

<h:form>
    <h:selectOneMenu value="#{bean.currentPage}" converter="pageConverter" onchange="submit()">
        <f:selectItems value="#{bean.pages}" var="page" itemLabel="#{page.name}" />
    </h:selectOneMenu>
    <h:commandButton value="submit" action="#{bean.handleNavigation}" style="display:none"/>
</h:form>

with

@FacesConverter("pageConverter")

and managed bean (@ManagedBean Bean) with

private List<Page> pages;
private Page selectedPage;

public String handleNavigation(){
    //do some job before navigation
    return (selectedPage == null) ? null : selectedPage.getUrl();
}

and model class

class Page {
    private String name;//title in links
    private String url;//JSF view-id
}

Navigation on a meaningful client button click

You can use your dropbox to keep the choice of user selection and have a button to perform navigation:

<h:form>
    <h:selectOneMenu value="#{bean.currentPage}" converter="pageConverter">
        <f:selectItems value="#{bean.pages}" var="page" itemLabel="#{page.name}" />
    </h:selectOneMenu>
    <h:commandButton value="Navigate" action="#{bean.performNavigation}"}/>
</h:form>

with the same model as above.

Navigation based on <h:link>s

Do you navigation jobs with simple <h:link>s:

<ul>
    <ui:repeat var="page" value="#{bean.pages}>
        <li>
            <h:link value="#{page.name}" outcome="#{page.url}" />
        </li>
    </ui:repeat>
</ul>

and style this menu accordingly.

SEO comments

SEO is increasingly important nowadays, so following its rules is essential. It is important to use an url rewriting solution in addition to naming on-page links with the (basic) Page class as above, so that the user sees www.site.com/contact-us in his browser and not www.site.com/contact.xhtml.

The simplest way to follow IMHO is to use Prettyfaces, which is a great solution, to my taste. It allows you to set up your rewritten urls very easily (and rewrite all your internal urls in JSF components).

To enhance your site SEO component you could introduce a field seoUrl in Page model class, and then have a Prettyfaces mapping which will show SEO-friendly url (i.e. www.site.com/contact-us) instead of JSF view-id (i.e. www.site.com/contact.xhtml) in web browser's address bar.

Edit - the dispute on the need for URL rewriting

Some background of SEO-friendly rules, as proposed by Google, which have reference to URL structure:

  1. Improve the structure of your URLs - it could also lead to better crawling of your documents by search engines (Google search engine optimization guide);
  2. Spending the time to make your URLs as simple as possible for both users and search engines. Some webmasters try to achieve this by rewriting their dynamic URLs to static ones (the same reference, italics mine);
  3. Use words in URLs (all future references are from the Google guide as well);
  4. Create a simple directory structure;
  5. Allow for the possibility of a part of the URL being removed.

And now a few of the general guidelines from SEO specialists:

  1. Creating Optimized URLs (Understanding SEO Friendly URL Syntax Practices);
  2. Static is the Way & the Light (11 Best Practices for URLs);
  3. Choose descriptive URLs whenever possible (URL Rules to Follow To Create SEO and User Friendly URLs), etc.

My examinations of the issue:

  1. If you are using a statically typed page, its URL could be www.site.com/contact-us.xhtml, but why would there be 6 excessive characters - www.site.com/contact-us would be better;
  2. Your facelet pages can be located in a deeply nested inner structure, like /pages/articles/general/how-to-do-jsf.xhtml, but it would be better to have and url like www.site.com/articles/how-to-do-jsf with path reflected in page, if necessary;
  3. Some developpers tend to use short filenames of facelets (jsf-bp.xhtml), or unmeaningful ones (article23.xhtml), but it would be better to show an url of www.site.com/article/jsf-best-practices-for-beginners;
  4. Usage of extensions, be it .xhtml, .jsf, etc. may lead users (and probably search engines) into thinking that the content is dynamic (meaning that content is rendered from a template), like in www.site.com/product.xhtml?id=12345, but static content should be preferred, as users (and probably search engines) would think that such an URL describes a compeletely stateless page, like in www.site.com/products/jsf-book-for-advanced-users. Moreover, it greately enhances site usability, which is also of great importance;
  5. People tend to use ids for query parameters (?id=12345) and names for path-parameters (/jsf-book-for-advanced-users);
  6. URL rewriting provides for a clear way to navigate your site. Imagine a path www.site.com/products/jsf-book-for-advanced-users: this type of url structure will render a unique product page, and removal of /jsf-book-for-advanced-users may render a complete catalogue. But what shall happen if you have www.site.com/product.xhtml?name=jsf-book-for-advanced-users for products and www.site.com/catalogue.xhtml for catalogue? The logic is unclear for a user, rewriting enables structuring of your URLs;
  7. Finally, most of the sites that deal with SEO do NOT use file extensions (and make little use of query parameters), as well as the site we are on, stackoverflow.com.

I do not claim that sources referred to by me are undisputable, or are extremely authorative, or their input needs to be applied to every web application, etc. but I do believe that well-structured, user-friendly sites that exist for a long time in production tend to follow those rules.