Wednesday, 15 June 2016

Creating your first android app - installation, configurations and app coding

Download android studio from this link:
Keep clicking next and follow basic instructions and install studio.
Now , create a new project:



Give an application name and company domain. Company domain is pretty much like package in java.


Since we are creating a mobile app, click on mobile/tablet option:


Choose the design template you wish to build upon. I am selecting Empty activity:

Activity Name is named by default as MainActivity, you can change it to anything relevant. This is the piece of code where you write your events code and click on finsih.

On clicking finish editor opens, navigate to MainActivity.



since screen shot is unclear, ill put the entire final code here: [refer to it at the end]

package com.example.jb.khushisoysterdemo1;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

        @Override        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
        public void onClickEvent(View v)
        {
            TextView txt=(TextView) (findViewById(R.id.textID1));
            txt.setText("Hey there, this is my 1st android app with event");
        }
    }


Now navigate to gradle.properties 


Edit it by removing the last comment, and adding an extra line, so that the last two lines are:
org.gradle.parallel=true
org.gradle.daemon=true

Now gradle.properties should be like:


Now go to File > Settings > Compiler
Add –offline at command-line options to run your app offline with the connected device


Now go to File > Settings > Build, Execution, Deployment > Build Tools > Gradle .
Tick mark “Offline work”.

Click on Apply and press OK.

Now go to res > layout > activity_main.xml


Click on Widgets > Button and drag button to phone screen on the right side.
                Label the button as testClick and let the id be buttonID1:


Now drag a Plain TextView from widget. On running this app at the end, this text box should appear/ be made visible in screen on click of “testClick” button.
Give text as textPlaceHolder and give id name as textID1.





We will use button and text widget ids to fire event on button click.
Now, go back to MainActivity and change onCreate to public instead of protected and add a function “onCllickEvent” to trigger on click of button “buttonID1”.

Now go back to activity_main.xml and double click on “testClick” button widget. Navigate to “onClick” proprty and select “onClickEvent”. 


Check mark “clickable”



Now to test your app wirelessly on your android device, you have to do following configuartions:
(wireless test on android device is supported from version 5 as per my understanding)
On your android device, navigate to:
Settings > About device and Click on build number 7 times.
Now go to Settings > Developer Options
And check mark “Authorise wireless display” (Check on this point, im not sure if this is compulsary, but i did it)
Note your ip from ADB over network.
NOW,
On your computer, navigate to:
C:\Users\User Name\AppData\Local\Android\Sdk\platform-tools
Now press shift and right click at same time and then select “open command window here”


Now type “adb devices” and click enter. Then write “adb connect ip_address”. In place of “ip_adress”, type in the above noted ip address of your phone and click enter.

U’ll get a reply saying its connected to the ip:

Once connected,
Build and Run your app.

For USB test on android app
-          To test your app on device with USB connection:
1.       Make sure your device driver is installed in your computer. For example, Samsung device driver is downloaded from http://www.samsung.com/in/support/usefulsoftware/KIES/.
2.       In your computer, navigate to:
C:\Users\UserName\AppData\Local\Android\Sdk
And double click on SDK Manager  and navigate to Extras and check mark “Google USB Driver”:

Install it.
Then build the project:


Connect your android device with  your laptop. You should be able to see your connected device as blue highlighted in this screenshot:

Click OK.

Next, run it and you should be able to see this new app in your android device



Now click on TESTCLICK to see the text message



Tuesday, 3 May 2016

Private VS Final in java

Private
Final

Possible
Example/Other comments.
Possible
Example/Other comments.
Class
N
Only private inner classes are possible.
Y
Final class cannot be inherited
Variable
Y
Private variables cannot be read outside class without being accessed by its own class method.
Y
An initialized final variable cannot be changed ever.

Uninitialized Instance final  variable
- An unitialized final variable MUST be initialized either ONLY in instance block, in which case you cannot initialize it even in constructors.
ELSE if there is no instance block, it MUST be initialized in  ALL its constructors, failing which there is compile time error.

Uninitialized static  final variable
-  I observed that there was a compile time error on declaring a final static variable without being initialized. Initializing it even in static method would not solve the error.
Constructor
Y
If you make a constructor private, you restrict the implicit/default call of super constructor and thus you restrict class being inherited and you restrict object creation of the class having private constructor. So you cannot create an object of a class with private constructor.
N
Constructors cannot be final.
Error:
Illegal modifier for the constructor in type parentClass; only public, protected & private are permitted
Method
Y
You cannot override a private method. Nor can you access a private method from outside class. You can access private method if another methof of same class calls the private method, in which case you can create object of class and call the method which in turn calls private methods.
Y
A final method cannot be overridden. Can be tested with help of upcasting.

Monday, 21 March 2016

Handling back and forward navigation of your webpage by clearing cache

Now you have a system which has popup modals for editing row level data. On cancelling the pop-up modal, you are back at the previous page. However, on clicking browser back button, the edit popup modal pops up. Which is clearly not the flow of screens you would like. So to avoid that, you can use interceptors to avoid cache memory to store URLs which you do not want to be navigated back.

So, lets say you have a main page: itemManagement.jsp and on edit, the URL is itemManagement/edit.html. edit.htl opens up teh pop-up modal. On cancelling that, if you press back button, you would like to skip edit.html. You can do so by simply adding interceptors in spring config file:

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="itemManagement/edit.html/*"/>
             <mvc:mapping path="itemManagement/edit.html"/>
            <bean id="webContentInterceptor" class="org.springframework.web.servlet.mvc.WebContentInterceptor">
                <property name="cacheSeconds" value="0"/>
                <property name="useExpiresHeader" value="true"/>
                <property name="useCacheControlHeader" value="true"/>
                <property name="useCacheControlNoStore" value="true"/>
            </bean>
        </mvc:interceptor>
    </mvc:interceptors> 

Thats pretty much it. Now on clicking back or forward buttons, edit screen does not pops up again, because you have disabled cache storing for this URL. Your browser depends on cache to navigate back and forward to pages but if you disable cache, those pages are skipped while browsing back or forward from your browser's navigation.

Saturday, 6 February 2016

Elaborate explanation on part of a Elopade DB design structure

Elopade Database design follows a very crisp structure.

Each table created has an automated procedure linked to it which gives it a "Table ID". You cannot create a table ID unless that table ID is registered to a module. This gives flexibility to have different levels of admin and super users.

1st - we create a table to store user detail. This table initially has only firstname, lastname, uid , pswd, email, modifiedby and createby to store. But after we create 2 more tables, we alter this table to add new columns - table id and roleID. I am deliberately creating this table initially without these columns as at this point table from which tableid needs to be referenced is not yet created. So follow the steps, which may look messy at first but works out just fine.

Just for clarity purpose i have added a naming convention to tables and procedures(which i personally detest to do ) but it is vital, somehow.

so here we go:

create table to hold users detail (note: at this point i have not added createdby, modifiedby or tableid, which i do after few more queries):

create table admin_m_users
(
firstname varchar(50),
lastname varchar(50),
uid varchar(30) primary key,
pwd varchar(200),
emailID varchar(30),
createdDate timestamp,
modifiedDate timestamp
)

create a procedure to auto update insert date. Modified date is saved from the backend program and not with the procedure. Honestly, my stack memory went low so i could not create a trigger for after update. I had increased stack memory to 1 GB in pg config file,, but it wasnt working. So my workaround - I update modified date from application and then save it as a value in DB:

NOTE: Our encryption happens in procedure:

CREATE OR REPLACE FUNCTION admin_after_insert_admin_m_users()
RETURNS TRIGGER
AS $BODY$ BEGIN
IF new.createby IS NULL
THEN
        UPDATE admin_m_users
        SET createdDate = current_timestamp,  createby = new.uid, modifiedby = new.uid,
        pwd = crypt(NEW.pwd, gen_salt('bf'))
 WHERE uid = new.uid;
 ELSE
         UPDATE admin_m_users
        SET createdDate = current_timestamp,
        pwd = crypt(NEW.pwd, gen_salt('bf'))
 WHERE uid = new.uid;
 END IF;
 RETURN NEW;
 END;
$BODY$ LANGUAGE plpgsql;


Trigger to execute above procedure:

CREATE TRIGGER admin_trigger_Afterinsert_admin_m_users AFTER INSERT ON admin_m_users
FOR EACH ROW EXECUTE PROCEDURE admin_after_insert_admin_m_users();

Now, lets just insert a value in admin_m_users:
insert into admin_m_users values
('U01', 'PswdNew@007', 'khushboo@elopade.com');

Now you can test and see if created date is auto filled.

Next,
we create a table to link modules with tables. Each table ever created will be registered here. admin_m_users too will get registered here, after which i alter table admin_m_users to add table ID:

create table admin_m_moduleTableLink
(
moduleID varchar(30) NOT NULL,
tableID varchar(30) NOT NULL,
ModuleWithtableDescription varchar(60) UNIQUE,
createBy varchar(30)references admin_m_users(uid),
modifiedBy varchar(30)references admin_m_users(uid),
createdDate timestamp,
modifiedDate timestamp,
CONSTRAINT compositePair PRIMARY KEY (moduleID,tableID)
)

Procedure:

CREATE OR REPLACE FUNCTION admin_after_insert_admin_m_moduleTableLink()
RETURNS TRIGGER
AS $BODY$ BEGIN
        UPDATE admin_m_moduleTableLink
        SET ModuleWithtableDescription = concat(moduleID, tableID), createdDate = current_timestamp
 WHERE moduleID = new.moduleID and tableID = new.tableID;
 RETURN NEW;
 END;
$BODY$ LANGUAGE plpgsql;

Trigger:

CREATE TRIGGER admin_trigger_Afterinsert_admin_m_moduleTableLink AFTER INSERT ON admin_m_moduleTableLink
FOR EACH ROW EXECUTE PROCEDURE admin_after_insert_admin_m_moduleTableLink();

Now register all the tables which will be or can be created:

insert into admin_m_moduleTableLink
values
(
'UserProfile', 'admin_m_encrypt'
);

insert into admin_m_moduleTableLink
values
(
'UserProfile', 'admin_m_users'
);

insert into admin_m_moduleTableLink
values
(
'UserProfile', 'admin_m_roles'
);

insert into admin_m_moduleTableLink
values
(
'UserProfile', 'admin_m_module_usrRelation'
);

insert into admin_m_moduleTableLink
values
(
'Goods', 'admin_m_itemMaster'
);

insert into admin_m_moduleTableLink
values
(
'Goods', 'admin_m_itemBOM'
);


insert into admin_m_moduleTableLink
values
(
'Partner', 'admin_m_businessPartner'
);





Now 'modulewithtabledescription' will be used as tableID in all respective tables:

Now create table for roles, permission values are restricted to Y(yes) and N(No).
Different combinations can define different level of privileges. Admin will have all Y.

create table admin_m_roles
(
roleID varchar(30) primary key,
mread varchar(1),
tableID varchar(40) references admin_m_moduleTableLink(ModuleWithtableDescription),
minsert varchar(1),
mupdate varchar(1),
mdelete varchar(1),
createBy varchar(30)references admin_m_users(uid),
modifiedBy varchar(30)references admin_m_users(uid),
createdDate timestamp,
modifiedDate timestamp,
CHECK  ((mread = 'Y' or mread = 'N' ) and (minsert = 'Y' or minsert = 'N') and (mupdate = 'Y' or mupdate = 'N')
and (mdelete = 'Y' or mdelete = 'N'))
)

Procedure to audo fill table id and create date:

CREATE OR REPLACE FUNCTION admin_after_insert_admin_m_roles()
RETURNS TRIGGER
AS $BODY$ BEGIN
        UPDATE admin_m_roles
        SET tableID = 'UserProfileadmin_m_roles', createdDate = current_timestamp  
  WHERE roleID = new.roleID;
 RETURN NEW;
 END;
$BODY$ LANGUAGE plpgsql;

trigger for above procedure:

CREATE TRIGGER admin_trigger_Afterinsert_admin_m_roles AFTER INSERT ON admin_m_roles
FOR EACH ROW EXECUTE PROCEDURE admin_after_insert_admin_m_roles();

Now delete procedure admin_after_insert_admin_m_users. (Keep following what i say here):

Delete trigger :admin_trigger_Afterinsert_admin_m_users

ALTER TABLE admin_m_users
ADD tableID varchar(40) references admin_m_moduleTableLink(ModuleWithtableDescription),
ADD createBy varchar(30)references admin_m_users(uid),
ADD modifiedBy varchar(30)references admin_m_users(uid),
ADD roleID varchar(30) references admin_m_roles(roleID);

Note: Now admin_m_users have role added to it along with others above.


Now recreate procedure and trigger for admin_m_users:

CREATE OR REPLACE FUNCTION admin_after_insert_admin_m_users()
RETURNS TRIGGER
AS $BODY$ BEGIN
IF new.createby IS NULL
THEN
        UPDATE admin_m_users
        SET createdDate = current_timestamp, tableID = 'UserProfileadmin_m_users', createby = new.uid, modifiedby = new.uid,
        pwd = crypt(NEW.pwd, gen_salt('bf'))
 WHERE uid = new.uid;
 ELSE
         UPDATE admin_m_users
        SET createdDate = current_timestamp, tableID = 'UserProfileadmin_m_users',
        pwd = crypt(NEW.pwd, gen_salt('bf'))
 WHERE uid = new.uid;
 END IF;
 RETURN NEW;
 END;
$BODY$ LANGUAGE plpgsql;
Trigger:

CREATE TRIGGER admin_trigger_Afterinsert_admin_m_users AFTER INSERT ON admin_m_users
FOR EACH ROW EXECUTE PROCEDURE admin_after_insert_admin_m_users();

Now link role with tables:

create table admin_m_module_usrRelation
(
tableID2 varchar(40) references admin_m_moduleTableLink(ModuleWithtableDescription),
tableID varchar(40) references admin_m_moduleTableLink(ModuleWithtableDescription), -- procedure
roleID varchar(30)references admin_m_roles(roleID),
createBy varchar(30)references admin_m_users(uid),
modifiedBy varchar(30)references admin_m_users(uid),
createdDate timestamp,
modifiedDate timestamp,
CONSTRAINT compositePair1 PRIMARY KEY (tableID2,roleID)
)

Usual procedure and trigger:

CREATE OR REPLACE FUNCTION admin_after_insert_admin_m_module_usrRelation()
RETURNS TRIGGER
AS $BODY$ BEGIN
        UPDATE admin_m_module_usrRelation
        SET tableID = 'UserProfileadmin_m_module_usrRelation', createdDate = current_timestamp
 WHERE roleID = new.roleID and tableID2 = new.tableID2;
 RETURN NEW;
 END;
$BODY$ LANGUAGE plpgsql;

CREATE TRIGGER admin_trigger_Afterinsert_admin_m_module_usrRelation
    AFTER INSERT ON admin_m_module_usrRelation
    FOR EACH ROW
    EXECUTE PROCEDURE admin_after_insert_admin_m_module_usrRelation();

Create Item Master, Restrict Item type to P(Parent), C(Child), PC(ParentAndChild):

 create table admin_m_itemMaster
(
tableID varchar(40) references admin_m_moduleTableLink(ModuleWithtableDescription),
itemID varchar(30) primary key,
itemName varchar(40),
itemType varchar(2),
createBy varchar(30)references admin_m_users(uid),
modifiedBy varchar(30)references admin_m_users(uid),
createdDate timestamp,
modifiedDate timestamp,
totalCost float,
CHECK  (itemType = 'P' or itemType = 'C' or itemType = 'PC')
)

Procedure to autolink it to registered table ID:

CREATE OR REPLACE FUNCTION admin_after_insert_admin_m_itemMaster()
RETURNS TRIGGER
AS $BODY$ BEGIN
        UPDATE admin_m_itemMaster
        SET tableID = 'Goodsadmin_m_itemMaster', createdDate = current_timestamp   
 WHERE itemID = new.itemID;
 RETURN NEW;
 END;
$BODY$ LANGUAGE plpgsql;

 Trigger:

CREATE TRIGGER admin_trigger_Afterinsert_admin_m_itemMaster
    AFTER INSERT ON admin_m_itemMaster
    FOR EACH ROW
    EXECUTE PROCEDURE admin_after_insert_admin_m_itemMaster();

Create Business Partener:

create table admin_m_businessPartner
(
tableID varchar(40) references admin_m_moduleTableLink(ModuleWithtableDescription),
BP_ID varchar(30) primary key,
BP_Type varchar(2),
BP_Name varchar(30),
createBy varchar(30)references admin_m_users(uid),
modifiedBy varchar(30)references admin_m_users(uid),
createdDate timestamp,
modifiedDate timestamp,
CHECK  (BP_Type = 'C' or BP_Type = 'V' or BP_Type = 'CV')
)


CREATE OR REPLACE FUNCTION admin_after_insert_admin_m_businessPartner()
RETURNS TRIGGER
AS $BODY$ BEGIN
        UPDATE admin_m_businessPartner
        SET tableID = 'Partneradmin_m_businessPartner', createdDate = current_timestamp
 WHERE BP_ID = new.BP_ID;
 RETURN NEW;
 END;
$BODY$ LANGUAGE plpgsql;

CREATE TRIGGER admin_trigger_Afterinsert_admin_m_businessPartner
    AFTER INSERT ON admin_m_businessPartner
    FOR EACH ROW
    EXECUTE PROCEDURE admin_after_insert_admin_m_businessPartner();

Create a BOM table. This table links parent and child items and with relevant metrics. I have written the procedure in a such way that a parent Item should be registered as type 'P' in admin_m_item table:

create table admin_m_itemBOM
(
itemID varchar(30) NOT NULL,
parentID varchar(30) NOT NULL,
quantity int,
quantityUnit varchar(20),
price float,
vendorID varchar(30),
tableID varchar(40) references admin_m_moduleTableLink(ModuleWithtableDescription),
createBy varchar(30)references admin_m_users(uid),
modifiedBy varchar(30)references admin_m_users(uid),
createdDate timestamp,
modifiedDate timestamp,
CONSTRAINT itemID PRIMARY KEY (itemID,parentID),
CONSTRAINT itemIDF FOREIGN KEY (itemID)
REFERENCES admin_m_itemMaster (itemID),
CONSTRAINT parentIDF FOREIGN KEY (parentID)
REFERENCES admin_m_itemMaster (itemID),
CONSTRAINT vendorID FOREIGN KEY (vendorID)
REFERENCES admin_m_businessPartner (BP_ID)
)

Procedure:

CREATE OR REPLACE FUNCTION admin_after_insert_admin_m_itemBOM()
RETURNS TRIGGER
AS $BODY$ BEGIN
        UPDATE admin_m_itemBOM
        SET tableID = 'Goodsadmin_m_itemBOM',createdDate = current_timestamp  
 WHERE (itemID = new.itemID and parentID = new.parentID) and parentID IN (select itemID from admin_m_itemMaster where itemType = 'P');
delete from admin_m_itemBOM where tableID IS NULL;
 RETURN NEW;
 END;
$BODY$ LANGUAGE plpgsql;


Note: If parent ID is not among registered parent item, i delete the row in the above procedure.

Trigger to run above procedure:

CREATE TRIGGER admin_trigger_Afterinsert_admin_m_itemBOM
    AFTER  INSERT ON admin_m_itemBOM
    FOR EACH ROW
    EXECUTE PROCEDURE admin_after_insert_admin_m_itemBOM();

Tuesday, 26 January 2016

Passing a JSON Array Object from AJAX to Spring controller class and retrieving individual values to make dashboard even more intuitive

Now what if I want to change my dashboard according to new values selected in dropdowns in dashboard? Well, to do just just that you can pass your single value or object value to the class using AJAX and JSON and then retrieve the new dashboard values based on selected options. In this example I will show you how to pass JSON Arrays and then parse it in spring controller class to retrieve each value individually.

Project Structure:


web.xml
-----------------------------------

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <servlet>
    <servlet-name>sdnext</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/config/sdnext-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>sdnext</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
</web-app>

sdnext-servlet.xml
--------------------------------------------------

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
">


 <context:component-scan base-package="com.login" />
 <mvc:annotation-driven/>
<mvc:resources mapping="/resources/**" location="/resources/img" />
<mvc:resources mapping="/js/**" location="/js" />
<mvc:resources mapping="/css/**" location="/css" />




  <mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
            <property name="prefixJson" value="true"/>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

 <bean id="jspViewResolver"
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass"
   value="org.springframework.web.servlet.view.JstlView" />
  <property name="prefix" value="/WEB-INF/views/" />
  <property name="suffix" value=".jsp" />
 </bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
  <property name="webBindingInitializer">
    <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"/>
  </property>
  <property name="messageConverters">
    <list>
      <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
    </list>
  </property>
</bean>
</beans>

Index.jsp
----------------------------------------------
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
    <%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
  <form:form method="POST" action="ajaxPage.html">
     <table>
      <tr>
        <td colspan="2"><input type="submit" value="Submit"/></td>
       </tr>
   </table>
  </form:form>
 

</body>
</html>


ajax.js
-------------------------------------------------
var k = 0;


$(document).ready(function(){


     callAjax();
   
     $('#submit').click(function(event) {
         $("#re").empty();
         var arr =  {"ar1": [
{
"firstName": "Khushboo",
"lastName": "Singh"
},
{
"firstName": "Khushi",
"lastName": "Singh"
}
]
};
       
       
    $.ajax({
        type: 'POST',
        //    dataType: 'json',
        contentType:'application/json',
        url: "ajax.html",
        data: JSON.stringify(arr),
        success: function(response) {  
        alert("success");     
            var jsonType = JSON.parse(response);
            alert("jsonType "+ jsonType);
             $.each(jsonType, function(key,value){
         alert("key "+key);
                 for(var i = 0; i < value.length; i++)
                     {
                       $("#re").append("<tr><th>"+key.toUpperCase()+"</th><td>"+value[i]+"</td></tr>");
                     }           
             });
            },
        error: function(xhr, textStatus, errorThrown){
        alert('request failed'+errorThrown);
        }
        });

            });
   
});

function callAjax() {
    $("#re").empty();
     var arr =  {"ar1": [
{
"firstName": "Khushboo",
"lastName": "Singh"
},
{
"firstName": "Khushi",
"lastName": "Singh"
}
]
};
   
   
    $.ajax({
        type: 'POST',
        //    dataType: 'json',
        contentType:'application/json',
        url: "ajax.html",
        data: JSON.stringify(arr),
        success: function(response) {  
            alert("success");   
            var jsonType = JSON.parse(response);
            alert("jsonType "+ jsonType);
             $.each(jsonType, function(key,value){
                  alert("key "+key);
                       for(var i = 0; i < value.length; i++)
                     {
                       $("#re").append("<tr><th>"+key.toUpperCase()+"</th><td>"+value[i]+"</td></tr>");
                     }           
             });
            },
        error: function(xhr, textStatus, errorThrown){
        alert('request failed'+errorThrown);
        }
        });


     }   

LoginController.java
----------------------------------------------------

package com.login.controller;

import java.io.IOException;

import java.util.ArrayList;

import javassist.bytecode.Descriptor.Iterator;


import org.apache.catalina.User;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.type.TypeFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;


import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import antlr.collections.List;

import com.google.gson.Gson;
import com.google.gson.JsonParser;
import com.login.bean.testArrayListInAjax;


@Controller
public class LoginController {

 testArrayListInAjax obj1 = null;

 @RequestMapping(value = "/ajaxPage")
 public ModelAndView forwordLogin() {
 
  return new ModelAndView("ajax");
 }

 @RequestMapping(value = "/ajax")
 public @ResponseBody
 String ShowUserDetails(@RequestBody String arr1) {
     Gson gson = new Gson();
/*Note: Now i slice out the String arr1 to the format needed to convert String to JSONArray.*/
    int first = arr1.indexOf("[");       
    int last = arr1.lastIndexOf("]")+1;
    String l = arr1.substring(first, last);   
    ArrayList FirstNames = new ArrayList();
    ArrayList LastNames = new ArrayList();
     try {
         JSONArray jsonarray = new JSONArray(l);
         System.out.println("jsonarr "+jsonarray);
            for(int i=0; i < jsonarray.length(); i++) {
                JSONObject jsonobject = jsonarray.getJSONObject(i);
                String firstName       = jsonobject.getString("firstName");
                String lastName    = jsonobject.getString("lastName");
               FirstNames.add(firstName);
               LastNames.add(lastName);
               //Do whatever manipulation now you want to do with each individual value.     
             
                }
    } catch (JSONException e) {
        // TODO Auto-generated catch block
        System.out.println("catch");
        e.printStackTrace();
    }
    
     obj1 = new testArrayListInAjax();
      obj1.setAr1(FirstNames);
      return gson.toJson(obj1);
 }

 @RequestMapping(value = "/index", method = RequestMethod.GET)
 public ModelAndView welcome() {

  return new ModelAndView("index");
 }


}

testArrayListInAjax
-----------------------------------------

package com.login.bean;

import java.util.ArrayList;

public class testArrayListInAjax
{

    ArrayList ar1 = new ArrayList();

    public ArrayList<String> getAr1()
    {
        return ar1;
    }

    public void setAr1()
    {
        ar1.add("ArrayValue1");
        ar1.add("ArrayValue2");
       
    }   
   
    public void setAr1(ArrayList a)
    {
       
        ar1.add(a.get(0));
        ar1.add(a.get(1));
       
    }   
   
}

ajax.jsp
----------------------------------
  <?xml version="1.0" encoding="ISO-8859-1" ?>
 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<script type="text/javascript" src="./js/jquery.js"></script>
<script type="text/javascript" src="./js/ajax.js"></script>



</head>

<body>

 <table>
      <tr>
       <td colspan="2"> 
 <select id="param1">
  <option value="Khushboo">Khushboo</option>
  <option value="Singh">Khushi</option>

</select>
</td>
 <td colspan="2">
 <select id="param2">
  <option value="singh">Singh</option>
  <option value="Singh">Singh</option>
</select>
</td>
 <td colspan="2">
 <button type="button" id = "submit">submit</button>
</td>
</tr>
</table>




<table id="re" name="re" border="2" cellspacing="4" cellpadding="4">

</table>


</body>
</html>

Index screen
------------------------------


Now in my scenario I have explained how to pass a JSON array and then individually retrieve the values but i have not really changed the values based on parameters. But you can do that using this very code but instead of passing a static array you can pass the parameters individually. Using this code you can dynmaically change table values using AJAX and JSON. This is just the brief cut out on what i will be implementing in my dashboard in order to make it even more intuitive.


Thursday, 21 January 2016

Making Morris graph from bootstrap dashboard theme dynamic in spring application using AJAX and JSON

In my personal home project, I am using bootstrap dashboard theme after login:

http://startbootstrap.com/template-overviews/sb-admin-2/ 

 After login I was able to pass a single data from controller class to dashboard page, however it was a huge learning for me to be able to integrate morris charts with multiple arrays passed in an object from controller class.

So, in this blog I will show you how to pass an array object containing multiple arrays to the dashboard page in above link in order for the "Morris.Area" graph to display data according to the arrays in passed objects using AJAX and JSON. Go through my previous blog to see how to pass simple array from controller class to another JSP page using AJAX.

If you download the bootstrap theme from the given link, i have modified pages/index.html to views/dashboard.jsp in my example as my project structure is different. So you will have to configure paths accordingly.

arrayBean.java
---------------------------
package com.c.bean;

import java.util.ArrayList;

public class arrayBean
{


    ArrayList<String> period = new ArrayList<String>();
    ArrayList<Integer> iphone = new ArrayList<Integer>();
    ArrayList<Integer> ipad = new ArrayList<Integer>();
    ArrayList<Integer> itouch  = new ArrayList<Integer>();
    public ArrayList<String> getPeriod() {
        return period;
    }
    public void setPeriod() {
        period.add("2010 Q1");
        period.add("2010 Q2");
        period.add("2010 Q3");
        period.add("2010 Q4");
        period.add("2011 Q1");
        period.add("2011 Q2");
        period.add("2011 Q3");
        period.add("2011 Q4");
        period.add("2012 Q1");
        period.add("2012 Q2");
    }
    public ArrayList<Integer> getIphone() {
        return iphone;
    }
    public void setIphone() {
   
        iphone.add(2666);
        iphone.add(2778);
        iphone.add(4912);
        iphone.add(3767);
        iphone.add(6810);
        iphone.add(5670);
        iphone.add(4820);
        iphone.add(15073);
        iphone.add(10687);
        iphone.add(8432);
        }
    public ArrayList<Integer> getIpad() {
        return ipad;
    }
    public void setIpad() {
        ipad.add(0);
        ipad.add(2294);
        ipad.add(1969);
        ipad.add(3597);
        ipad.add(1914);
        ipad.add(4293);
        ipad.add(3795);
        ipad.add(5967);
        ipad.add(4460);
        ipad.add(5713);
    }
    public ArrayList<Integer> getItouch() {
        return itouch;
    }
    public void setItouch() {
        itouch.add(2647);
        itouch.add(2441);
        itouch.add(2501);
        itouch.add(5689);
        itouch.add(2293);
        itouch.add(1881);
        itouch.add(1588);
        itouch.add(5175);
        itouch.add(2028);
        itouch.add(1791);
    }

}

controller class - ControllerClass.java
--------------------------------------------------------

// This is the url linked to submit button on Index page


 @RequestMapping(value = "/save", method = RequestMethod.POST)
 public ModelAndView saveUser( @ModelAttribute("loginBean1") RegisterBean loginBean) {

//some code 
  return new ModelAndView("dashboard");
 }

 @RequestMapping(value = "/dashboard")
 public @ResponseBody
 String ShowUserDetails() {
Gson gson = new Gson();
arrayBean o1 = new arrayBean();
o1.setPeriod();
o1.setIpad();
o1.setIphone();
o1.setItouch();

return gson.toJson(o1);
 }

dashboard.js
------------------------------------

$(document).ready(function(){
 callAjax();

});

function callAjax() {

$.ajax({
       url : 'dashboard.html',       
       success : function(response) {
           var v = 0;
           var period1 = null;
           var iphone1 = null;
           var ipad1 = null;
           var itouch1 = null;
           var jsonType = JSON.parse(response);
           $.each(jsonType, function(key,value)
                   {
               if (v == 0)
                   {
                 
                    period1 = value;
                   v++;
           
                   }
               else if(v == 1)
                   {
                    iphone1 = value;
                   v++;
           
                   }
               else if(v == 2)
               {
                ipad1 = value;
               v++;
           
               }
               else if(v == 3)
               {
                itouch1 = value;
               v++;
       
               }
                   }
           
                 );         

    var data = [];
           for (var i = 0; i < 10; i++) {
             
              var x = {
                   period: period1[i],
                   iphone: iphone1[i],
                   ipad: ipad1[i],
                   itouch: itouch1[i]
               };
              data.push(x);
      
               }
          
       
          
           Morris.Area({
                element: 'morris-area-chart',
                data: data,
                xkey: 'period',
                ykeys: ['iphone', 'ipad', 'itouch'],
                labels: ['iPhone', 'iPad', 'iPod Touch'],
                pointSize: 2,
                hideHover: 'auto',
                resize: true
           });
    
       }
   });
}

From the standard page - pages/Index.jsp - I have removed external script call "<script src="./js/morris-data.js"></script> ", as, I have already manipulated the graph in dashboard.js and so calling this page would override the purpose of displaying a dynamic morris graph on dashboard.

Now the graph looks pretty much the same, with only difference that now the graph is dynamic.