Tuesday, September 6, 2011

Rich web Interfaces with DHTMLX and Google App Engine


Developers building applications on top of the Google App Engine for Java can choose between several frameworks to build rich user interfaces. This post illustrates how to create a simple CRUD application, using DHTMLX Java Tag Library and JPA. The sample provided starts by creating a UI skeleton, which incorporates the DHTMLX widgets, with the use of JavaScript, to integrate the widgets with server side code.


The User Interface 



The application major features are:
  • Dynamic Loading 
    Keeping thousand of records in a data grid is a common requirement for most applications. Smart Rendering increases overall performance with big amounts of data, activating a dynamic loading to fetch data from the server when needed.

  • Edit in place
    In the great book Designing Web Interface, written by Bill Scott and Theresa Neil, they underline the value of the Make It Direct principle, allowing the user to directly edit content in place.
  • Right Click Context Menu
    The Fitts's Law highlights the value to keep the tools close, to improve the user interaction. This principle has been applied providing a  context menu, so that the user can select a row and access the related functions (delete and insert in this case) using the right click.

Client 
To create the user interface the DHTMLX Java Tag Designer has been used (useful but not mandatory). You can find step by step instructions here. Below the HTML code of  the page.


  1. <%@ taglib uri="http://www.mylaensys.com/dhtmlx" prefix="dhtmlx" %>
  2. <html>
  3.  <head>
  4.   <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
  5.   <title></title>
  6.   <link href="dhtmlx.css" rel="stylesheet" type="text/css" />
  7.   <link href="dhtmlx_custom.css" rel="stylesheet" type="text/css" />
  8.   <style></style>          
  9.  </head>
  10.  <script type="text/javascript" src="dhtmlx.js"/>
  11.  <body>
  12.      <!-- body -->
  13.  </body>
  14. </html>
  15. <dhtmlx:body name='initializeDHTMLX' imagePath='imgs/'>
  16.   <dhtmlx:layout name='layout' id='content'  pattern='1C' >
  17.     <dhtmlx:layoutcell name='a' text='a' hideHeader='true'>
  18.       <dhtmlx:toolbar  name='toolbar'>
  19.         <dhtmlx:toolbarButton  id='button_ins' text='Insert Row'/>
  20.         <dhtmlx:toolbarButton  id='button_del' text='Delete Row'/>
  21.       </dhtmlx:toolbar>
  22.       <dhtmlx:grid   name='grid'>
  23.         <dhtmlx:column  name='sales' header='Sales' type='ed'/>
  24.         <dhtmlx:column  name='title' header='Title' type='ed'/>
  25.         <dhtmlx:column  name='author' header='Author' type='ed'/>
  26.         <dhtmlx:column  name='price' header='Price' type='ed'/>
  27.         <dhtmlx:menu name='grid_menu'>
  28.           <dhtmlx:menuChild  id='button_ins' text='Insert Row'/>
  29.           <dhtmlx:menuChild  id='button_del' text='Delete Row'/>
  30.         </dhtmlx:menu >
  31.      </dhtmlx:grid>
  32.      <dhtmlx:statusbar name="status"/>
  33.     </dhtmlx:layoutcell>
  34.   </dhtmlx:layout>
  35. </dhtmlx:body>
  36. <script language='JavaScript' type='text/javascript'>
  37.     function initialize() {
  38.         initializeDHTMLX();
  39.     }
  40.     dhtmlxEvent(window,'load', initialize);
  41. </script>

The user interface is declared within the <dhtmlx:body> tags, using a Layout component as container for the Toolbar,  Status Bar, and Grid. 


  1. var busy = false,sort_c = "",sort_d = "";
  2. function initialize() {
  3.    initializeDHTMLX();
  4.    toolbar.attachEvent("onClick", on_click );
  5.    grid_menu.attachEvent("onClick", on_click );
  6.    grid.attachEvent("onBeforeSorting", function(ind,type,direction){
  7.       if(!busy) {
  8.          sort_c = this.getColumnId(ind);
  9.          sort_d = ((sort_d == "des") ? "asc": "des");
  10.          load_data();
  11.          grid.setSortImgState(true,ind,direction);
  12.       }
  13.       return false;
  14.    });
  15.    grid.enableSmartRendering(true);
  16.    grid.enableValidation(true, true, true, true);
  17.    grid.setColValidators("ValidInteger,NotEmpty,NotEmpty,ValidInteger");
  18.    load_data();
  19.    dp = new dataProcessor("controller");
  20.    dp.setTransactionMode("POST");
  21.    dp.setUpdateMode("cell");
  22.    dp.enableDataNames(true);
  23.    dp.init(grid);
  24. }

In first step, the event handlers for toolbar and menu are attached to the components. The initialization proceed with the grid setup, enabling the SmartRendering, setting up the validation, and loading the data. OnBeforeSorting event handler attached to the grid  provides the support for server side sort processing.   
Last step of initialization, is the data processor configuration, which takes care to send back to the server updates that occurred on the grid; calling enableDataNames ensures that the column names will be included as parameters in the POST request. 
The two additional functions defined for toolbar/menu command handling  (on_click) and data loading (load_data) are visible below :

  1. function load_data() {
  2.    if( !busy ) {
  3.       grid.clearAll();
  4.       grid.loadXML("controller?orderby="+sort_c+"&dir="+sort_d);
  5.    }
  6. }
  7. function on_click(id) {
  8.    var selected = grid.getSelectedRowId();
  9.    if( null != selected) {
  10.       if( "button_ins" == id ) {
  11.   grid.addRow((new Date()).valueOf(),[0,'','',0],grid.getRowIndex(selected));
  12.       } else if( "button_del" == id ) {
  13.          var answer = confirm("Are you sure ?")
  14.          if (answer){
  15.             grid.deleteRow(selected);
  16.          }
  17.       }
  18.    }
  19. }


The load_data function resets the grid component  and sends an ajax  request (GET) to the server to retrieve the data. The on_click detects which button or menu item has been selected by the user and performs the corresponding operation.


Server
On the server side, the Java class Book is annotated for persistence, getter and setter omitted for short. You can see that the names of the attributes match the names of the columns.
  1. @PersistenceCapable(detachable = "true")
  2. public class Book {
  3.     @PrimaryKey
  4.     @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
  5.     private Long id;
  6.     @Persistent
  7.     private Integer sales;
  8.     @Persistent
  9.     private String title;
  10.     @Persistent
  11.     private String author;
  12.     @Persistent
  13.     private BigDecimal price;
  14. }


The doGet method of the servlet retrieves the data and feeds the grid. 

  1. public class ControllerServlet extends HttpServlet {
  2.  @Override
  3.  public void doGet(HttpServletRequest request,
                       HttpServletResponse response) throws IOException {
  4.       EntityManager em = EMF.get().createEntityManager();
  5.       try {
  6.          Integer start = new Integer(0);
  7.          Integer count = new Integer(maxrows);
  8.          Integer total = new Integer(0);
  9.          if (!isEmpty(request.getParameter("posStart"))) {
  10.           start = Integer.parseInt(request.getParameter("posStart"));
  11.          }
  12.          if (!isEmpty(request.getParameter("count"))) {
  13.            count = Integer.parseInt(request.getParameter("count"));
  14.            count = count > maxrows ? maxrows : count;
  15.          }
  16.          if (start.intValue() == 0) {
  17.            Query query = em.createQuery("select count(b) from " +
               Book.class.getName() + " b");
  18.            total = (Integer) query.getSingleResult();
  19.          }
  20.          String orderBy = getOrderBy(
             request.getParameter("orderby"), request.getParameter("dir")
             );
  21.          Query query = em.createQuery("select from " +
             Book.class.getName() + orderBy );
  22.          query.setFirstResult(start);
  23.          query.setMaxResults(count);
  24.          List<Book> books = query.getResultList();
  25.          response.setContentType("text/xml");
  26.          response.getWriter().print( toXML(total, start, books) );
  27.          response.getWriter().close();
  28.      } finally {
  29.          em.close();
  30.      }
  31.   }
  32.  }
  33. }


The smart rendering option, enabled during grid initialization, adds as parameters the starting position of the record (posStart) and the number of records to be returned (count). The doGet method processes these parameters plus sort parameters, if any, executes the query on the data store, and returns the retrieved rows as XML. 
Update operations are performed in the doPost method of the ControllerServlet :


  1. public class ControllerServlet extends HttpServlet {
  2.   @Override
  3.   protected void doPost(HttpServletRequest request,
                            HttpServletResponse response)
  4.      EntityManager em = EMF.get().createEntityManager();
  5.      try {
  6.         String action = "";
  7.         String id = request.getParameter("gr_id");
  8.         String type = request.getParameter("!nativeeditor_status");
  9.         Book book = new Book();
  10.         if ("inserted".equalsIgnoreCase(type)) {
  11.            action = "insert";
  12.            BeanUtils.populate(book, request.getParameterMap());
  13.            em.persist(book);
  14.            em.refresh(book);
  15.         } else {
  16.            Query query = em.createQuery("select from " + Book.class.getName()
                             + " where id = " + id);
  17.            book = (Book) query.getSingleResult();
  18.            if ("updated".equalsIgnoreCase(type)) {
  19.                action = "update";
  20.                BeanUtils.populate(book, request.getParameterMap());
  21.                em.persist(book);
  22.            } else if ("deleted".equalsIgnoreCase(type)) {
  23.                action = "delete";
  24.                em.remove(book);
  25.            }
  26.       }
  27.       if (!isEmpty(action)) {
  28.           response.setContentType("text/xml");
  29.           response.getWriter().print("<data><action type='" + action + "' sid='" + id + "' tid='" + book.getId() + "' /></data>");
  30.           response.getWriter().close();
  31.       }
  32.    } catch (Exception e) {
  33.        e.printStackTrace();
  34.    } finally {
  35.         em.close();
  36.    }
  37.  }


DHTMLX data processor component has its own protocol to exchange information with the server (additional information is available on DHTMLX website). This sample implementation, detects the operation triggered by the data processor and performs the appropriate data store operation.






40 comments:

  1. Replies
    1. The effectiveness of IEEE Project Domains depends very much on the situation in which they are applied. In order to further improve IEEE Final Year Project Domains practices we need to explicitly describe and utilise our knowledge about software domains of software engineering Final Year Project Domains for CSE technologies. This paper suggests a modelling formalism for supporting systematic reuse of software engineering technologies during planning of software projects and improvement programmes in Final Year Projects for CSE.

      Software management seeks for decision support to identify technologies like JavaScript that meet best the goals and characteristics of a software project or improvement programme. JavaScript Training in Chennai Accessible experiences and repositories that effectively guide that technology selection are still lacking.

      Aim of technology domain analysis is to describe the class of context situations (e.g., kinds of JavaScript software projects) in which a software engineering technology JavaScript Training in Chennai can be applied successfully

      The Angular Training covers a wide range of topics including Components, Angular Directives, Angular Services, Pipes, security fundamentals, Routing, and Angular programmability. The new Angular TRaining will lay the foundation you need to specialise in Single Page Application developer. Angular Training

      Delete
  2. Thanks to the admin you have spend a lot for this blog I gained some useful info for you. Keep doing. web design company in velachery

    ReplyDelete
  3. Aluminium Composite Panel or ACP Sheet is used for building exteriors, interior applications, and signage. They are durable, easy to maintain & cost-effective with different colour variants.

    ReplyDelete

  4. That's great about what you have expressed in this clear cut blog in sense of SEO , and yes this would make a wonderful blog. Here's a lot of technical and educational information plotted as in your writings, it was more understandable and easy to read.
    Sounds like something people would want to read this blog really!keep writing…

    seo training classes
    seo training course
    seo training institute in chennai
    seo training institutes
    seo courses in chennai
    seo institutes in chennai
    seo classes in chennai
    seo training center in chennai

    ReplyDelete

  5. Thanks for your extraordinary blog. Your idea for this was so brilliant. This would provide people with an excellent tally resource from someone who has experienced such issues. You would be coming at the subject from a different angle and people would appreciate your honesty and frankness. Good luck for your next blog!
    Tally ERP 9 Training
    tally classes
    Tally Training institute in Chennai
    Tally course in Chennai

    ReplyDelete
  6. Having read this I thought it was very enlightening. I appreciate you spending some time and energy to put this short article together studying. I once again find myself personally spending way too much time both reading and commenting. But so what, it was still worthwhile!

    ReplyDelete
  7. Thanks for sharing information. Choosing computer accessories from leading IT store offer great discount and value for your money Computer Store Australia | All in One Pc Australia

    ReplyDelete
  8. เราคือผู้นำด้านเกมพนันออนไลน์ Major168 เราคือผู้ให้บริการ คาสิโนออนไลน์ ที่ได้รับรองว่าดีที่สุดในประเทศไทย มีค่ายเกมส์ให้เล่นมากมาย Sagaming, Sexy bacarat, Dreamgame, Ebet, Wm casino, Vivo gaming ไม่ผ่านเอเย่นต์ ระบบปลอดภัยมีทีมงานดูแลตลอด 24ชม.

    SAGAME88 แหล่งรวมเกมส์พนันออนไลน์ คาสิโนสด บาคาร่า กำถั่ว คาสิโนออนไลน์ ไฮโล รูเล็ต รับเครดิตฟรีเล่นได้ทุกเกมส์ โบนัสสมาชิกใหม่เพียบ พร้อมระบบฝากถอนออโต้ 10วิ เรามีทุกค่ายเกมส์ให้คุณเลือกเดิมพัน SA Game Sexy bacarat Dreamgame WM Casino VIVO Gaming Ebet เล่นได้ทุกเกมส์

    Our website ufabet provides betting services in the system of Auto Deposit-Withdrawal. Our members are not only in Thailand. Online football betting UEFA Bet market And this makes a guarantee that Ufabet168 is another reliable football betting website

    ufa through the website UFABET1688 a web gambling online , one that integrated all the bets from online casinos , online casino , online , and also have a game a lot more to be chosen to play such games.

    ReplyDelete

  9. I am really happy to say it’s an interesting post to read . I learn new information from your article , you are doing a great job . Keep it up

    Devops Training in Hyderabad

    Hadoop Training in Hyderabad

    Python Training in Hyderabad

    Tableau Training in Hyderabad

    Selenium Training in Hyderabad

    ReplyDelete
  10. Here I am for the first time, and I found beneficial information. Very nice and well-explained article. Keep up the good work. Also, if you want to know about how to transfer Microsoft Office setup to a new PC, then click the link below:
    office.com/setup | office.com/setup | mcafee.com/activate | mcafee.com/activate | office.com/myaccount | www.mcafee.com/activate

    ReplyDelete
  11. If you encounter an issue that Orbi parental controls don’t support, then it is advisable to reset the Netgear router. Apart from this, you might accidentally change some files that might cause an error. In such a situation, it is advisable to reset the Orbi router in your home.

    ReplyDelete
  12. Thank you so much for sharing such an intresting blog with us.

    ReplyDelete
  13. Thanks for sharing informative post. Are looking for best Tamil typing tool online, make use of our Tamil typing software to make translation faster. Thirumana Porutham in Tamil | Samacheer Kalvi Books PDF

    ReplyDelete
  14. You have done a great job . keep up the good work .thanks for sharing nice information . Java Vogue have good examples on java . 

    ReplyDelete
  15. Incredible post I should say and a debt of gratitude is in order for the data. Schooling is certainly a tacky subject. Be that as it may, is still among the main subjects within recent memory. I appreciate your post and anticipate more. You have made some valid statements there. I looked on the web to study the issue and discovered a great many people will oblige your perspectives on this site...
    how to make a paper airplane eagle | how to make a boomerang airplane | the eagle paper airplane | best paper airplane design for distance and accuracy | best paper airplanes for distance and speed

    ReplyDelete