I’ve been adding Bootstrap and Angular to my existing Struts2 site. They improve the look and feel of the site and make it feel more responsive to the user. There are some issues though refactoring a Struts2 page-refresh style site to use Bootstrap and Angular. I think it is worth doing it though as you get a much nicer front-end. Ideally I would like to write the whole front end using Bootstrap and Angular and just use Struts2 as a framework for exposing Json services. That will require a lot of refactoring but I am slowly moving closer.
First of all – what are Bootstrap and Angular and what are their advantages.
For an example of how Bootstrap can be used to mobile optimise a page look at this page www.findfriendsforfun.com using a laptop. The main contents of the page are laid out in two columns each with two rows. Then shrink the browser down in width. Note that when it gets to mobile phone width the screen rearranges to be one column with four rows. Also the top menu disappears and is accessable via a button. This is all done using out of the box Bootstrap CSS classes.
For another example look at this page http://www.findfriendsforfun.com/register.action using a laptop. There is a form with labels on the left and fields on the right. Then shrink the browser down in width. Note that when it gets to mobile phone width the form rearranges so the labels move to above their fields and the fields take up the whole width of the screen. This is also done using out of the box Bootstrap CSS classes.
I have only used Angular in bits of http://www.findfriendsforfun.com that are only accessable to users that have logged in – so I can’t share a link to that here (but if you are keen enough – register, complete your profile and then go and have a look at the Search page J ). But a good example is where you are displaying a paging list of items. When the user clicks ‘Next’ the server queries the database to get the next page of data. Using straight Struts2 to display this next page to the user you need to refresh the whole page. This is a lot slower and also means the page flickers and jumps around. Using Angular the Next button makes a Ajax call to a Json service. When the Json service returns the data Angular replaces the old data with the new data. The rest of the page is not touched. This is faster and feels much nicer for the user.
Pain-points when applying to an existing Struts2 website.
Bootstrap has standard CSS styles for a lot of HTML tags. It also has a lot of CSS classes defined. These will probably conflict with your existing CSS file. My solution was to delete my existing CSS file and then add back in just what was necessary. This could involve a lot of work if you have a large site with a lot of CSS.
Bootstrap has a nice way of displaying forms that also responds to the screen width. But if you’ve developed all your existing forms using the default Struts2 theme xhtml (you will be using this if you haven’t specified anything else) then you won’t get those advantages. The xhtml theme lays forms out using a table, so it can’t rearrange depending on screen width, and obviously isn’t going to add the Bootstrap look and feel CSS classes unless you tell it too. If the only visible bit of your form is the submit button then you can make it look like a Bootstrap style button just by adding the Bootstrap CSS classes
to the s:submit tag. If your form has some visible fields and you want it to respond to the screen width – then one solution is to rewrite the form in straight HTML rather than using Struts tags.
<s:form action=”someAction” method=”post” >
<s:textfield name=”someFieldName” key=”some.key.someFieldName” size=”40″/>
<s:submit name=”something” key=”some.key.something” align=”center” />
<form id=”contactform” class=”form-horizontal”
<label class=”col-sm-5 control-label” for=”someFieldName”>Some Field</label>
<input type=”text” class=”form-control” placeholder=”Some Field” id=”someFieldName” name=”someFieldName” required/>
<div class=”col-sm-offset-5 col-sm-7″>
<input class=”btn btn-default” type=”submit” value=”Do Something”/>
If you choose to rewrite your forms in HTML as above – and you were using Struts2 XML validation files for the form – you’ll suddenly find that they don’t work anymore. More correctly – they do work – but they aren’t able to display error messages by the fields like they used to. From a users point of view – they click submit and nothing happens and they get no feedback as to why. If you want to continue using the Struts2 XML validation it would probably be possible to fix that if you wanted to dive into the HTML code the Struts tags create and add the relevant bits to your form. What I have done is removed the Struts XML validation completely and use the HTML5 validation options instead (ie <input type=”email” ….. required/> ). This works for most browsers and then I use server side validation for old browsers and malicious users who know how to get around client-side validation.
With Angular you can take a existing Struts2 page and change it to a Angular driven page using Ajax calls to update what’s on the page. It’s great – until you leave it to go to another page and then use the ‘Back’ button to go back to it. What you get then is the page as it was when the user first went to it. Ie if the Angular page had a list of paging data on it, the user pages to page 2, then clicks on ‘See this item’ for one of the items in the list, then clicks back – they will go back to the list on the first page of data. The way I have got around that is to use local storage http://gregpike.net/demos/angular-local-storage/demo/demo.html to save all the results of the Ajax calls made while the user is on the page. Every time you go to the Angular list page the first thing is does is check the local storage to see what the last state of the page was. Some points about this approach.
You need to guard against the case where User A uses the website then logs out. User B then uses the same computer and browser to visit the website. You don’t want User B to see User A’s data. To get around this I clear all local storage when a user first logs in and also store the user id with everything I put in local storage and check that.
I found the cookie bits of the angular-local-storage script were buggy. I created my own version of the script with all the cookie bits commented out.
It won’t work with old browsers. Old browsers will get the Angular page as it was when the user first visited it.
I’ve found Angular has issues with hidden input fields
<input type=”hidden” ….. />
Especially when using Chrome.
So I use
<input type=”text” style=”display: none;” ….. />