Showing posts with label JSF. Show all posts
Showing posts with label JSF. Show all posts

Tuesday, 19 May 2015

JSF Buttons Nested in a Repaintable Elements

There was a little bug in posts where any unsaved fields would be lost when removing a tag from the tag list. This happened because each tag element had <f:ajax render="@form" /> set.

Setting the JSF <f:ajax render="tags-output" /> had not facilitated the repainting of  the tag list. This was a problem and I thought <f:ajax render="@form" /> was the solution.

Armed with new knowledge about JSF  I have prefix the panelGroup's id with the form's id.

Now the bug has gone and the problem is solved.
    <ui:repeat var="t" value="#{postWriter.post.tags}">
        <h:commandButton
            value="#{t}"
            action="#{postWriter.removeTag(t)}"
        >
            <f:ajax
                render="posts:tags-output posts:tags"
            />
        </h:commandButton>
    </ui:repeat>

Thursday, 14 May 2015

General Settings

The general settings items are odd to model compared with the other entities that have been modeled within the blog platform.  The other entities created for the blog platform, such as 'Post' entities, can have n many instances persisted. If modeled this same way all settings would become one entity. Would it be better in this instance to persist each setting item individually?

I decided to try out modeling each setting individually for now. Here is what I have implemented.

JSF
     <label for="blog-desc">Blog Name</label>
    <h:inputText
        id="blog-name"
        value="#{configurationWriter.blogName}"
    >
        <f:ajax event="blur" />
    </h:inputText>

    <label for="blog-desc">Blog Description</label>
    <h:inputText
        id="blog-desc"
        value="#{configurationWriter.blogDescription}"
    >
        <f:ajax event="blur" />
    </h:inputText>



ConfigurationWriter.java
@Named("configurationWriter")
@ViewScoped
public class ConfigurationWriter implements Serializable {
    
    @Inject
    private ConfigurationDAOBean ps;
    private String blogName;
    private String blogDescription;
    
    @PostConstruct
    private void setup(){
        blogName = ps.fetch("blog-name").getValue();
        blogDescription = ps.fetch("blog-description").getValue();
    }
    
    public void save(){
        saveHelper("blog-name", blogName);
        saveHelper("blog-description", blogDescription);
    }
    
    private void saveHelper(String field, String value){
        Configuration c = ps.fetch(field);
        c.setValue(value);
        ps.store(c);
    }

    public String getBlogName() {
        return blogName;
    }

    public void setBlogName(String blogName) {
        this.blogName = blogName;
    }

    public String getBlogDescription() {
        return blogDescription;
    }

    public void setBlogDescription(String blogDescription) {
        this.blogDescription = blogDescription;
    }
}
   

ConfigurationDAOBean.java
@Stateless
public class ConfigurationDAOBean {

    @PersistenceContext
    private EntityManager em;

    public Configuration fetch(String item) {
        List<Configuration> results = em.createQuery("SELECT c FROM Configuration c WHERE c.name = :name", Configuration.class)
                .setParameter("name", item)
                .getResultList();
        
        if (results.isEmpty()) {
            Configuration c = new Configuration();
            c.setName(item);
            em.persist(c);
            return c;
        }
        
        return results.get(0);
    }

    public void store(Configuration c) {
        em.merge(c);
    }
}

I am open to ideas!

Saturday, 9 May 2015

Page URLs With Breakaway Binding

Creating a basic implementation of the 'Pages' functionality gave me an idea for how to handle the dynamic URLs. First, URLs need a default suggestion. Second page authors need the option to create there own URL.

A page's URLs should default to the page's title. Spaces are replaced by hyphens. Diacritic marks will also need to be handled correctly. For now diacritic marks are on the backlog.

The URL property within the entity class is indirectly updated by changes to the title. The indirection allows for string replacement to happen. The string replacement ensure compliant URLs for each page.
    <h:inputText
        value="#{pageWriter.page.title}"
        id="title"
        >
        <f:ajax event="keyup"
                listener="#{pageWriter.updateURL()}"
                render="url"
                disabled="#{pageWriter.page.freestyleUrl}"
        />
        <f:ajax event="blur"
                disabled="!#{!pageWriter.page.freestyleUrl}"
        />
    </h:inputText>
When in freestyle mode fewer ajax requests are needed and therefore made by disabling/enabling the 'keyup' and 'blur' events respectively; as can be seen above.

As well as a default URL, it is nice to let authors create their own URL. Allowing a freestyle URL as well as a default URL involves a breakaway binding. This binding needs to be linked and unlinked at the author's will.

Here is the JSF checkbox's declaration.
    <h:selectBooleanCheckbox value="#{pageWriter.page.freestyleUrl}">
        <f:ajax
            event="change"
            render="url"
        />
    </h:selectBooleanCheckbox>
This checkbox switches the freestyle mode.

Here is the JSF URL input field's declaration.
    <h:inputText
        class="form-control" 
        id="url"
        disabled="#{!pageWriter.page.freestyleUrl}"
        value="#{pageWriter.page.url}"
    >
        <f:ajax 
            event="blur"
            render="url"
            execute="url"
            disabled="#{!pageWriter.page.freestyleUrl}"
        />
    </h:inputText>
The blog platform's page entities now have following fields:
  • url
  • freestyleURL
  • title
  • description
  • body (i.e. the content of the page)
  • created by etc. will come later.
Here is the end result:


Sunday, 3 May 2015

Displaying 'No Pages'

Using JSF's ui:fragment wrapper element is easy to display a 'No pages' message.  This is what I have came up with:

PageDAOBean.java
    [...]

    public int countAllPages(){
        Query q = em.createQuery("SELECT count(p) FROM Page p");
        Number result = (Number) q.getSingleResult();
        return result.intValue();
    }

    [...]


Pages.java (a JSF helper class)
    [...]

    public int countAll(){
        return pb.countAllPages();
    }

    [...]

pages.xhtml (JSF)
    [...]

    <ui:fragment rendered="#{pages.countAll() == 0}" >
        <h:outputText value="No pages yet. Why not add a page now?" />
    </ui:fragment>
                
    <ui:fragment rendered="#{pages.countAll() > 0}" >
        Doing now :-)
    </ui:fragment>

    [...]


I have been using this pattern on each of the list pages. If you know of a better way, feel free to let me know.

Saturday, 2 May 2015

Pages

Blogs normally have one or two pages. An example of what I mean by a page would be an 'about' page.

For now the blog platform's pages will include the following fields:
  • Title
  • Description
  • Body (i.e. the content of the page)
The view will be implemented on the front-end. The back-end will have the create, update, and delete functionality.

The URL pattern to retrieve a page in the front-end will be:

/<hyphenated page title>.html

I will use the page's title to query the database for the record. The .html URL ending will give the regex a solid stopping point. This will let the Java container 404 more invalid requests. Only the requests that match the pattern will hit the database. For the invalid requests that do hit the database something akin to this should do for raising a 404 page not found.

public void findPage(Long id) throws IOException {
        page = ps.getPageById(id);
        if (page == null) {
            FacesContext.getCurrentInstance().getExternalContext().responseSendError(HttpServletResponse.SC_NOT_FOUND, "page not found");
            FacesContext.getCurrentInstance().responseComplete();
        }
    }

Anyway, time to implement it.