Wednesday, 31 July 2013

When to use AngularJS and when to use Backbone!

In this post I am documenting my thoughts on when to use Backbone vs AngularJS with the help of examples (This post is not a comparison between AngularJS and Backbone).

E-Commerce Application

It should not be a single page app (unless we are trying to address few small use-cases or building shopping site for a small merchant). 

We need a framework which provides support for data-binding. Struts OGNL, Spring MVC, JSF EL etc work fine but these are backend technologies. For a modern web-app we need similar support using JavaScript. AngularJS from Google offers this kind of functionality and hence recommended. 

Online HTML/CSS Builder 

Edit functionality becomes more important than view/read. It should be a single page app (User experience is good in this case). 

A lot of UI specific work involved - like drag n' drop, animation effects etc. Text rendering is limited. AngularJS can be used to create a SPA but Backbone is recommended.

Interactive Reporting Tool

Dynamic UI, report editing and cool UI effects. Backbone is recommended. Please not that Backbone alone is not sufficient so we must use a suitable js-tech-stack which is known to work properly with Backbone.

Content Management System

Data representation in TEXT format. Edit functionality using regular forms. 
Single Page App with content getting managed in various Views. AngularJS is recommended.

Question - What will I use if I have to build GMail? 
Answer - AngularJS :)

* In most of the projects where I use Backbone, I define proper architecture for the JS layer, design with the help of a complete js-tech-stack and let backbone play its role (I do not let backbone drive the architecture of front-end).

Friday, 26 July 2013

My Findings with ModelDriven Struts Action

We are well aware of the usual action classes of Struts- values of the fields entered in UI populate the corresponding action properties. In case of ModelDriven action class, the properties of its model class get populated. Here is an example of it:


public class EmployeeRegistrationAction extends ActionSupport implements ModelDriven<EmployeeData>{

 private EmployeeData employeeData = new EmployeeData();

 
 public EmployeeData getModel() {
  return employeeData;
 }

 //Rest of the methods

}


public class EmployeeData implements Serializable{

 private String firstName;
 private String lastName;
 private String city;

 //setters & getters

}


The next step is to implement the getModel() method in such a way that it returns the application domain object, in our example we return the EmployeeData object. We can either use ModelDriven<Object>, where getModel will return Object or can specify the model class as above.
Prerequisite for using such action class is that it should implement ModelDriven interface, for which Model Driven Interceptor should be applied to action. Since this interceptor is part of the default interceptor stack, it is applied to all actions by default. Wow...we don't have to do anything out of the way to use it!

JSP:

<s:form method="POST" action="/registration.html" name="registrationform" enctype="multipart/form-data" id="registrationform">

     <s:textfield name="firstName" placeholder="First Name"/>
     <s:textfield name="lastName" placeholder="Last Name"/>
     <input type="submit" class="button" value="Create Employee"/>

</s:form>


Since I did not want to navigate to any other page and wanted the json response by staying on same page, I used ajaxSubmit(). I'd used ajaxSubmit earlier too and json response was returned just as I expected. Xml entry:

<action name="registration" class="employeeRegistrationAction" method="createEmployeeRecord">

 <result type="json"></result>

</action>


Javascript:

var registrationFormOptions = {

 resetForm : false,// reset the form after successful submit
        success   : showRegistrationResponse

    };


$("#registrationform").validate({

 submitHandler:function(form){
 //perform not-null validations. If fine,submit. else show validation error messages
 $(form).ajaxSubmit(registrationFormOptions);

 }
});

But in case of ModelDriven, json response that I was getting, was surrounded by <pre style="word-wrap: break-word; white-space: pre-wrap;"> tag. I thought of extracting json sitting inside the <pre> tag, in javascript. Thankfully I was saved from it, just one minor addition and it worked:


var registrationFormOptions = {

 resetForm : false,// reset the form after successful submit
 success : showRegistrationResponse,
 dataType: 'json'
};


Addition of dataType: 'json' in the options worked wonders. I was getting a clean json response!


Monday, 8 July 2013

Don't eval(Javascript)

I was looping through the Department data-departmentVO_1 to departmentVO_5 (each contained DepartmentVO complexType's object) and display info against the respective department.


for ( var x = 1; x < 5; x++) {

   var info = "departmentVO_"+x;

   var department = data.info;

   $("#totalEmployeesDepartment_"+x).val(department.departmentVO.totalEmployees);

}

Surprisingly javascript was throwing error for department being undefined. That indicated data.info was not working as I expected.

I searched for concatenating loop variable to access a variable in javascript and found out that something on this line would work:


eval('var department = ' +data.info);

w3schools says: The eval() function evaluates or executes an argument.
If the argument is an expression, eval() evaluates the expression. If the argument is one or more JavaScript statements, eval() executes the statements.

But misuse of eval has led to serious concerns like security issues or performance issue or often simple bugs. Also each invocation of eval() creates a new instance of the JavaScript interpreter and hence creation of new execution context. In short additional resource being put to use. Plus such code is harder to debug and maintain (Reminds me of 'goto' statement...we can still use it, but difficult to find problems). So it is better to check if there is any better, neater and safer alternative.

I decided not to use eval in my case. Understanding what I was trying to obtain, I realized that square brackets can be used instead of literal dot-names. So my code:


var department = data.info;

replaced with

var department = data[info];

I'm convinced, so lets use eval with care!

Thursday, 4 July 2013

Struts + Ajax + JSON

It wasn't my first experiment with Struts or Ajax or jsp! Despite this fact, I ran into problems and had to spend time to fix it. So let me share what dawned to me (I'm specifically avoiding term 'what I learnt'...since I already knew it).

My home.action had jsp with div in it which would open as a popup with a link click.

<s:textfield id="fullName" value="%{datamodel.fullName}" placeholder="Full Name"/>
In brief, on click of the link, it was supposed to show the div with values populated, fetched from db.

Action class with a method to serve my need was already in place to fetch data and populate in bean. However the action was returning another jsp. Using the same method in Action class, making an additional entry which returned result type as json, did the job.

<action name="homePage" class="HomePageAction" method="loadUserData">
     <result type="json"></result>
</action>

I wrote a function to send ajax request (to be called with link click):

function loadData(index){

var userName = $("#userName").val();

$.ajax({

type: "GET",

url : '/site/loadUserData.action?userName ='+userName,

success: function(data){

     showProfile();

   }

 });

}

I was getting 'data' in success part of ajax request. Happy! I was expecting the bean values to be displayed on the pop up since bean is populated and popup opens after that. But I continued to see blank fields. Disheartened!

The reason behind it was straightforward(though it didn't trigger me while I was working on it!): jsp got rendered when home.action was called. That time bean was not having values. Jsp displayed/resolved the values it had at that time. Now when I click link, send ajax request, get json response, how would jsp be aware of that!

Setting the values of fields on success of ajax(), before opening the pop up call was the way out:

$.ajax({

type: "GET",

url : '/site/loadUserData.action?userName ='+userName,

success: function(data){

showProfile(data.profileVO);

  }

 });

function showProfile(profileVO){

  $("#fullName").val(profileVO.fullName);

}


Happy ajaxing & struting(strutting ;) ).