I am trying to fill the table with both column headers and its body with data, however it fails to make the ajax call if.
<table id="datatable1" cellpadding="0" cellspacing="0" border="0" class="display" width="100%">
<thead>
</thead>
<tbody>
</tbody>
</table>
I leave both the head and body empty.
But adding some random title.
<thead>
<tr>
<th>Random column title</th>
</tr>
</thead>
fixes it. Though I mean to add both the column names and the data at the same time from a JSON string and add it to the table it won't let me :
I am also able to load stuff from the database no problem if the proper aoColumns and mData are established beforehand.
var oTable; //datatable reference
var start = 0; //first row's id to load
var qty = 100; //number of rows to load
var DESC = "false"; //load last row first and go down?
var type = "something";
var ajaxURL = GLOBAL_ROUTE + "api/application/datatable/fillTable/" + type + "/" + start + "/" + qty + "/" + DESC;
oTable = $('#datatable1').dataTable({
"sPaginationType" : "full_numbers",
"sDom" : '<"top"<"length"l><"search"f><"position">>rt<"bottom"<"info"i><"pages"p>>',
"bProcessing" : false,
"bServerSide" : false,
"sAjaxSource" : ajaxURL,
"bDeferRender" : true,
/*"aoColumns" : [ {
"mData" : "a"
}, {
"mData" : "b"
}, {
"mData" : "c"
}, {
"mData" : "d"
} ]*/
});
alert("asasd"); //this alert is not even reached if no header/body/aoColumns are set.
Any way around this without making an ajax call beforehand with the column names?
Nvm, I found the way and I'll share it with ya!
All I had to do was change the way I was making the ajax call. Instead of using the datatables "sAjaxSource" parameter to do it, I made my own jquery $.ajax() call to load absolutely everything via json.
First I changed the js code:
$.ajax({
"url" : ajaxURL,
"success" : function(json) {
json.bDestroy = true;
json.sPaginationType = "full_numbers";
json.sDom = '<"top"<"length"l><"search"f><"position">>rt<"bottom"<"info"i><"pages"p>>';
oTable = $('#datatable1').dataTable(json);
},
"dataType" : "json"
});
Then I had to make some changes on the data table object.
Here's the java code :
import java.util.List;
public class DataTableObject {
String sPaginationType = "";
String sDom = "";
boolean bProcessing = false;
boolean bServerSide = false;
String sEcho;
int iTotalRecords;
private List<Object> aoColumns;
List<Object> aaData;
public String getsPaginationType() {
return sPaginationType;
}
public void setsPaginationType(String sPaginationType) {
this.sPaginationType = sPaginationType;
}
public String getsDom() {
return sDom;
}
public void setsDom(String sDom) {
this.sDom = sDom;
}
public boolean isbProcessing() {
return bProcessing;
}
public void setbProcessing(boolean bProcessing) {
this.bProcessing = bProcessing;
}
public boolean isbServerSide() {
return bServerSide;
}
public void setbServerSide(boolean bServerSide) {
this.bServerSide = bServerSide;
}
public int getiTotalRecords() {
return iTotalRecords;
}
public void setiTotalRecords(int iTotalRecords) {
this.iTotalRecords = iTotalRecords;
}
public String getsEcho() {
return sEcho;
}
public void setsEcho(String sEcho) {
this.sEcho = sEcho;
}
public List<Object> getAaData() {
return aaData;
}
public void setAaData(List<Object> aaData) {
this.aaData = aaData;
}
public List<Object> getAoColumns() {
return aoColumns;
}
public void setAoColumns(List<Object> aoColumns) {
this.aoColumns = aoColumns;
}
}
So yeah, apparently I had to make an outside ajax call, but not two as I thought I might have to do in the end.
Hope this might be of help to someone in the future :)
K, back to work.
Since you're using Java on the back end, instead of playing with workarounds, you might want to consider the many examples provided on the JED website that demonstrate how best to work with DataTables on the Java platform. Check out: http://jed-datatables.net
Related
Please advise on C# syntax, I am doing Rest API Call toward PlayFab to get a player profile and then get assign the player display name to a local public variable, BUT during execution the sequence of function I found that they are not sequential at all. I don't understand why, as in python or java, all function is sequential and they will be executed after another function has completed.
By the logic, it should execute start function with OnLoginWithGoogleAccountPlayFab which will call GetPlayerProfile fetch the player name and assign on a public string PlayerDisplayName, then call ChangeSceneOnNewPlayer which will check for name if it is null.
But it executes this way enter image description here
public PlayerDisplayName;
void Start(){
OnLoginWithGoogleAccountPlayFab();
}
public void OnLoginWithGoogleAccountPlayFab() {
PlayFabClientAPI.LoginWithGoogleAccount(new LoginWithGoogleAccountRequest()
{
TitleId = PlayFabSettings.TitleId,
ServerAuthCode = AuthCode,
CreateAccount = true
}, (result) =>
{
PlayFabId = result.PlayFabId;
SessionTicket = result.SessionTicket;
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- --------------------- GET PROFILE 1");
GetPlayerProfile();
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- ---------------------NAME 1 ");
ChangeSceneOnNewPlayer();
}, OnPlayFabError);
}
public void GetPlayerProfile() {
PlayFabClientAPI.GetPlayerProfile(new GetPlayerProfileRequest()
{
PlayFabId = PlayFabId,
ProfileConstraints = new PlayerProfileViewConstraints()
{
ShowDisplayName = true,
}
}, (result) =>
{
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- ---------------------PROFILE 2");
Debug.Log("The player's DisplayName profile data is: " + result.PlayerProfile.DisplayName);
PlayerDisplayName = result.PlayerProfile.DisplayName;
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- ---------------------PROFILE 3");
}, OnPlayFabError);
}
public void ChangeSceneOnNewPlayer() {
Debug.Log("Player Info");
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- ---------------------NAME 2 ");
if (PlayerDisplayName == null) {
Debug.Log("Player Info is NULL " + PlayerDisplayName);
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- ---------------------NAME 3 ");
SceneManager.LoadSceneAsync("New_Player", LoadSceneMode.Single);
} else {
Debug.Log("Player Info NOT null " + PlayerDisplayName);
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- ---------------------NAME 3 ");
SceneManager.LoadSceneAsync("City", LoadSceneMode.Single);
}
}
Your methods are being executed sequentially, but the results you get back are returned asynchronously. This introduces race conditions to your code and is the reason you see the ChangeSceneOnNewPlayer method being executed before you have received the player profile.
Let's break down what's happening in the following lines (debugging removed for clarity):
// Both these lines execute synchronously.
PlayFabId = result.PlayFabId;
SessionTicket = result.SessionTicket;
// Here you're invoking a synchronous method, but inside the method
// an asynchronous call is made to PlayFab, and the result will not be immediately
// returned.
GetPlayerProfile();
// Then you immediately call this method, but you haven't waited for the result from
// PlayFab before you make this call.
ChangeSceneOnNewPlayer();
What you want is something more like this:
public PlayerDisplayName;
void Start()
{
OnLoginWithGoogleAccountPlayFab();
}
public void OnLoginWithGoogleAccountPlayFab()
{
PlayFabClientAPI.LoginWithGoogleAccount(new LoginWithGoogleAccountRequest()
{
TitleId = PlayFabSettings.TitleId,
ServerAuthCode = AuthCode,
CreateAccount = true
}, (result) =>
{
PlayFabId = result.PlayFabId;
SessionTicket = result.SessionTicket;
// Get the profile, and specify a callback for when the result is returned
// from PlayFab.
GetPlayerProfile(OnGetPlayerProfile);
}, OnPlayFabError);
}
public void GetPlayerProfile(Action<PlayerDisplayName> onGetPlayerDisplayName)
{
PlayFabClientAPI.GetPlayerProfile(new GetPlayerProfileRequest()
{
PlayFabId = PlayFabId,
ProfileConstraints = new PlayerProfileViewConstraints()
{
ShowDisplayName = true,
}
}, onGetPlayerDisplayName, OnPlayFabError);
}
// This method is used as a callback to your GetPlayerProfile function and is used
// to process the information.
public void OnGetPlayerProfile(PlayerDisplayName playerDisplayName)
{
PlayerDisplayName = playerDisplayName;
if (PlayerDisplayName == null)
{
SceneManager.LoadSceneAsync("New_Player", LoadSceneMode.Single);
}
else
{
SceneManager.LoadSceneAsync("City", LoadSceneMode.Single);
}
}
This is a standard pattern when using any RESTful API calls.
I am working on a JHipster project with an AngularJS front-end and a Java back-end. I am using Spring data with the MongoDb database.
I did a grouping operation on the field budgetCode. So, for each budgetCode, I succeded to have the list of all the linked taskCodes.
Here, the method aggregateAllTaskCodes which does the grouping operation:
Repository layer
public class ClarityResourceAffectationRepositoryImpl implements ClarityResourceAffectationRepositoryCustom {
#Override
public List<ClarityResourceAffectationReport> aggregateAllTaskCodes() {
Aggregation aggregation = newAggregation(
group("budgetCode").addToSet("budgetCode").as("budgetCode").addToSet("taskCode").as("taskCode"),
sort(Sort.Direction.ASC, previousOperation(),"budgetCode"));
AggregationResults groupResults = mongoTemplate.aggregate(aggregation, ClarityResourceAffectation.class,
ClarityResourceAffectationReport.class);
List<ClarityResourceAffectationReport> clarityResourceAffectationReports = groupResults.getMappedResults();
return clarityResourceAffectationReports;
}
}
Service layer
public class ClarityResourceAffectationServiceImpl implements ClarityResourceAffectationService{
#Override
public List<ClarityResourceAffectationReport> aggregateAllTaskCodes() {
log.debug("Request to aggregateByCodeBudgetForCodeTache : {}");
List<ClarityResourceAffectationReport> result = clarityResourceAffectationRepository
.aggregateAllTaskCodes();
return result;
}
}
REST API layer
public class ClarityResourceAffectationResource {
#GetMapping("/clarity-resource-affectations/list-task-codes")
#Timed
public ResponseEntity<List<ClarityResourceAffectationReport>> aggregateTabAllTaskCodes() {
log.debug("REST request to get aggregateTabAllTaskCodes : {}");
List<ClarityResourceAffectationReport> result = clarityResourceAffectationService.aggregateAllTaskCodes();
return new ResponseEntity<>(result, HttpStatus.OK);
}
}
ClarityResourceAffectation
#Document(collection = "clarity_resource_affectation")
public class ClarityResourceAffectation implements Serializable {
#Id
private String id;
#Field("budget_code")
private String budgetCode;
#Field("task_code")
private String taskCode;
public String getBudgetCode() {
return budgetCode;
}
public void setBudgetCode(String budgetCode) {
this.budgetCode = budgetCode;
}
public String getTaskCode() {
return taskCode;
}
public void setTaskCode(String taskCode) {
this.taskCode = taskCode;
}
}
ClarityResourceAffectationReport
public class ClarityResourceAffectationReport implements Serializable {
private static final long serialVersionUID = 1L;
private String budgetCode;
private String taskCode;
private String listTaskCode;
public String getBudgetCode() {
return budgetCode;
}
public void setBudgetCode(String budgetCode) {
this.budgetCode = budgetCode;
}
public String getTaskCode() {
return taskCode;
}
public void setTaskCode(String taskCode) {
this.taskCode = taskCode;
}
public String[] getListTaskCode() {
return listTaskCode;
}
public void setListTaskCode(String[] listTaskCode) {
this.listTaskCode = listTaskCode;
}
}
clarity-resource-affectation.service.js
(function() {
'use strict';
angular
.module('dashboardApp')
.factory('ClarityResourceAffectation', ClarityResourceAffectation);
ClarityResourceAffectation.$inject = ['$resource'];
function ClarityResourceAffectation ($resource) {
var resourceUrl = 'clarity/' + 'api/clarity-resource-affectations/:id';
return $resource(resourceUrl, {}, {
'query': { method: 'GET', isArray: true},
'aggregateAllTaskCodes': {
method: 'GET',
isArray: true,
url: 'clarity/api/clarity-resource-affectations/list-task-codes'
}
});
}
})();
When I call the function in the AngularJS front-end and I display that on a table, for each budgetCode, I have the list of the taskCodes in an array of one element. For example, for the budgetCode [ "P231P00"] I can have this list of taskCodes: [ "61985" , "43606" , "60671" , "43602"]
Well, I would like to have the list of the linked taskCodes, not in an array of one element but in an array of several elements like that:
[ ["61985"] , ["43606"] , ["60671"] , ["43602"] ]
What do I have to change in my code in order to do that?
Just for information, my javascript code which create the array based on the aggregate function:
clarity-resource-affectation-list-task-codes.controller.js
(function() {
'use strict';
angular
.module('dashboardApp')
.controller('ClarityResourceAffectationTableauBordNbCollaborateursController', ClarityResourceAffectationTableauBordNbCollaborateursController);
ClarityResourceAffectationTableauBordNbCollaborateursController.$inject = ['$timeout', '$scope', '$stateParams', 'DataUtils', 'ClarityResourceAffectation'];
function ClarityResourceAffectationTableauBordNbCollaborateursController ($timeout, $scope, $stateParams, DataUtils, ClarityResourceAffectation) {
var vm = this;
//Call of the function
allTaskCodes()
function allTaskCodes()
{
ClarityResourceAffectation.aggregateAllTaskCodes(function(readings) {
var dataAllTaskCodes;
dataAllTaskCodes = [];
alert(readings);
readings.forEach(function (item) {
dataAllTaskCodes.push({
label: item.budgetCode,
value: item.taskCode,
listvalue: item.listTaskCode
});
});
vm.dataAllTaskCodes = dataAllTaskCodes;
});
}
}
})();
Temporary solution:
Actually, I found a temporary solution by completing the method I created in the Service Layer:
#Override
public List<ClarityResourceAffectationReport> aggregateAllTaskCodes() {
log.debug("Request to aggregateAllTaskCodes : {}");
List<ClarityResourceAffectationReport> result = clarityResourceAffectationRepository
.aggregateAllTaskCodes();
Iterator<ClarityResourceAffectationReport> iterator = result.iterator();
while (iterator.hasNext())
{
ClarityResourceAffectationReport resAffectationReport = iterator.next();
String taskCodes = resAffectationReport.getTaskCode();
//Delete all exept letters, numbers and comma
taskCodes = taskCodes.replaceAll("[^a-zA-Z0-9,]","");
String[] listTaskCodes = taskCodes.split(",");
resAffectationReport.setListTaskCodes(listTaskCodes);
}
return result;
}
Also, I added an additional field to ClarityResourceAffectationReport which is listTaskCode. I updated the report class above. Finally, when I do an alert:
alert(readings[1].listvalue[0]), I have a result like 2630. So, I succeeded to have the first taskCode of a particular budgetCode.
I understood that what is important here is not the fact that as I told above for a budgetCode like [ "P231P00"], I must have a list like: [ "61985" , "43606" , "60671" , "43602"] or [ ["61985"] , ["43606"] , ["60671"] , ["43602"] ]. I just must have an array, not a string.
When I display alert(readings[1].listvalue), I have["2630","61297","61296","61299"] which is clearly an array because I can access each of the elements by calling alert(readings[1].listvalue[0]), alert(readings[1].listvalue[1]], etc...
I tried what you advised me
But, it is still not working. Here, my repository code:
#Override
public List<ClarityResourceAffectationReport> aggregateAllTaskCode() {
AggregationOperation project = new AggregationOperation() {
#Override
public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) {
return new BasicDBObject("$project", new BasicDBObject("budgetCode", "$budget_code").append("taskCode", Arrays.asList("$task_code")));
}
};
Aggregation aggregation = newAggregation(project,
group("budgetCode").addToSet("budgetCode").as("budgetCode").addToSet("taskCode").as("taskCode"),
sort(Sort.Direction.ASC, previousOperation(),"budgetCode"));
AggregationResults groupResults = mongoTemplate.aggregate(aggregation, ClarityResourceAffectation.class,
ClarityResourceAffectationReport.class);
List<ClarityResourceAffectationReport> clarityResourceAffectationReports = groupResults.getMappedResults();
log.debug("clarityResourceAffectationReports.size() => " + clarityResourceAffectationReports.size());
log.debug("aggregation.toString() => " + aggregation.toString());
return clarityResourceAffectationReports;
}
Here, you can find the logs:
clarityResourceAffectationReports.size() => 1
aggregation.toString() => {"aggregate" : "__collection__" , "pipeline" : [ { "$project" : { "budgetCode" : "$budget_code" , "taskCode" : [ "$task_code"]}} , { "$group" : { "_id" : "$budgetCode" , "budgetCode" : { "$addToSet" : "$budgetCode"} , "taskCode" : { "$addToSet" : "$taskCode"}}} , { "$sort" : { "_id" : 1 , "budgetCode" : 1}}]}
Thanks in advance
You need to use $project to change the taskCodes value into array of single value before $group.
I don't see any hook in the api to address this.
You can use AggregationOperation to create $project stage using mongodb (BasicDBObject) types.
AggregationOperation project = new AggregationOperation() {
#Override
public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) {
return new BasicDBObject("$project", new BasicDBObject("budgetCode", 1).append("taskCode", Arrays.asList("$taskCode")));
}
};
Something like
Aggregation aggregation = newAggregation(project,
group("budgetCode").addToSet("budgetCode").as("budgetCode").addToSet("taskCode").as("taskCode"),
sort(Sort.Direction.ASC, previousOperation(), "budgetCode"));
Using lambda
Aggregation aggregation = newAggregation(
aggregationOperationContext -> new BasicDBObject("$project", new BasicDBObject("budgetCode", 1).append("taskCode", Arrays.asList("$taskCode"))),
group("budgetCode").addToSet("budgetCode").as("budgetCode").addToSet("taskCode").as("taskCode"),
sort(Sort.Direction.ASC, previousOperation(), "budgetCode"));
I'm using the Parse API to query some data for an Android application and I would like to know how to return a value (for example a Boolean) from a Parse Query. For example I would like a function that returns true if some data exists and false otherwise like so :
public Boolean myFunction(){
ParseQuery<ParseObject> query = ParseQuery.getQuery();
query.findInBackground("someData",new GetCallback<ParseObject>() {
#Override
public void done(ParseObject lan, ParseException e) {
if(e==null){
return true;
} else {
return false;
}
});
}
I do know that this cannot be done this way because the query is processed in a background thread and I'm not very familiar with Callbacks.
I am aware that there is a similar question here Parse.com how to get return value of query but this is for JavaScript.
Do you have any idea on how to do that ?
You are almost there. When you get the Parse Object extract it with:
boolean myBoolean = myParseObject.getBoolean("myBooleanColumn");
Full example (finding an object via id, it can be adapted for other type of queries):
ParseQuery<ParseObject> query = ParseQuery.getQuery("YourClass");
query.getInBackground("id", new GetCallback<ParseObject>() {
public void done(ParseObject myParseObject, ParseException e) {
if (e == null) {
boolean myBoolean = myParseObject.getBoolean("myBooleanColumn");
} else {
// something went wrong
}
}
});
Update: if you only want to check if some data exists in a row you can do it with
query.whereEqualTo("columnToFind", "searchterm");
You can even find compare an array with the data in row with
query.whereContainsAll("columnToFind", arrayOfThingsToSearch);
After some research and thanks to #buckettt, the easiest way to accomplish that is to use Parse Cloud Code. Define your function in the main.js file inside parse-server folder :
Parse.Cloud.define("myFunction",function(req,res){
var userId = req.params.userId; //params passed in Client code
var myQuery = new Parse.Query(Parse.User);
myQuery.equalTo("userId", userId);
myQuery.find({
success: function(results) {
res.success(results.get("userName"));
}
error: function() {
res.error("Failed !");
}
}
});
And in your Client's code :
HashMap<String, Object> params = new HashMap<String, Object>();
params.put("userId",userId);
ParseCloud.callFunctionInBackground("myFunction", params, new FunctionCallback<String>() {
public void done(String res,ParseException e){
if (e == null) {
Log.i("Results :",res);
} else {
Log.i("Error",e.getMessage());
}
}
});
This way you return the desired value and the function is executed directly on your server. Hope this helps
I am using an aggregate query in mongodb to find the sum of an attribute in all the documents present in a collection.
Query:
db.conversation.aggregate( [
{
$match:{
$and:[{"mailBoxId":"1","isHidden":false}]
}
},
{
$group:
{
_id: {"mailBoxId":"$mailBoxId","isHidden":"$isHidden"} ,
messageCount: { $sum:"$messageCount" }
}
}
]);
The result returned by Mongodb is fine and is in this format.
{
"result" : [
{
"_id" : {
"mailBoxId" : "2",
"isHidden" : false
},
"messageCount" : 2
}
],
"ok" : 1
}
I just want the messageCount field. I am using MongoTemplate(Spring) class to query the database.
Query retrievalQuery = new Query();
retrievalQuery.addCriteria(Criteria.where("mailBoxId").is(userId).and("isHidden").is(false));
return mongoTemplate.find(retrievalQuery, );
I am confused how to store the resultant object returned by Mongodb and extract a specific field from it.
Pls help.
The way you are trying to use aggregate in mongoTemplate is wrong . Try this i am sure it will help.
Aggregation agg = Aggregation.newAggregation(
Aggregation.match(
Criteria.where("mailBoxId").is("1").and("isHidden").is(false)),
Aggregation.group("$mailBoxId").sum("$unReadMessagesCount").as("unReadMessagesCount")
);
System.out.println("Query ==>>["+agg.toString()+"]");
AggregationResults<AggResultObj> data = mongoTemplate.aggregate(agg, "collectionName", AggResultObj.class);
System.out.println("UnReadMesasgeCode :"+data.getUniqueMappedResult().getUnReadMessagesCount());
The AggResultObj will be looks like
public class AggResultObj{
String _id;
int unReadMessagesCount;
public String get_id() {
return _id;
}
public void set_id(String _id) {
this._id = _id;
}
public int getUnReadMessagesCount() {
return unReadMessagesCount;
}
public void setUnReadMessagesCount(int unReadMessagesCount) {
this.unReadMessagesCount = unReadMessagesCount;
}
}
For more information you can see my blog where i have created a example for the same for your scenario. please click https://satishkumardangi.blogspot.in/2016/09/using-mongo-db-aggregation-with-spring.html
Try this
Query retrievalQuery = new Query();
retrievalQuery.addCriteria(Criteria.where("mailBoxId").is(userId).and("isHidden").is(false));
var result = mongoTemplate.find(retrievalQuery);
var final = result[1].messageCount;
return final;
Here I have created dynamic dropdown list using this link, but when I select some value from available list it should be called in action class.
The dropdown list which can be seen in the image ,here the values are loaded dynamically from the database and now what I want is when I select any value from that two dropdown list that values (I mean text value) should be sent to the action class and there I will execute one JDBC select query on the basis of this two values and will display in the table shown in the image but everything should be on load.Action should be on selecting values from dropdown list not on any button click .With static values I am able to call value from dropdown list into action class with name attribute.But in this case I cannot :(
I hope I am clear now .
I have tried calling select tag using listkey,name and id but none of them worked .
Below is my JSP code:
<div>
<div class="invoicetext1">Event Name :</div>
<s:select name="dp.eventState"
list="%{state}"
class="billlistbox1"
id="eventName" />
<div>
<s:select name="dp.companyState"
class="billlistbox2"
listKey="companyState"
list="%{status}">
</s:select>
</div>
<div class="invoicetext2">Company Name :</div>
<div class="clear"></div>
</div>
<s:form action="ActionSelect">
<s:submit value=" Click Here"/>
</s:form>
<div>
Action class for loading dynamic dropdown list :
package com.ca.actions;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import com.ca.database.Database;
import com.ca.pojo.Event;
import java.sql.PreparedStatement;
import com.opensymphony.xwork2.ActionSupport;
public class RetrieveEvNaCoNaAction extends ActionSupport {
private static final long serialVersionUID = -5418233715172672477L;
List<Event> dataForBillsJspList;
private List state = new ArrayList();
private List status = new ArrayList();
String eventName;
public String getEventName() {
return eventName;
}
public void setEventName(String eventName) {
this.eventName = eventName;
}
public RetrieveEvNaCoNaAction() {
// TODO Auto-generated constructor stub
}
public List<Event> getDataForBillsJspList() {
return dataForBillsJspList;
}
public void setDataForBillsJspList(List<Event> dataForBillsJspList) {
this.dataForBillsJspList = dataForBillsJspList;
}
public List getStatus() {
return status;
}
public void setStatus(List status) {
try {
Database database = new Database();
Connection con = database.Get_Connection();
PreparedStatement ps = con
.prepareStatement("SELECT EVENT_NAME,COMPANY_NAME,date_format(FROM_DATE,'%d/%m/%Y') as dateAsFrom,date_format(TO_DATE,'%d/%m/%Y') as dateAsTo FROM EVENT");
ResultSet rs = ps.executeQuery();
//dataForBillsJspList = new ArrayList<Event>();
while (rs.next()) {
/*dataForBillsJspList.add(new Event(rs.getString("EVENT_NAME"),
rs.getString("COMPANY_NAME"), rs
.getString("dateAsFrom"), rs
.getString("dateAsTo")));
System.out.println(rs.getString("EVENT_NAME"));*/
status.add(rs.getString("COMPANY_NAME"));
}
System.out.println("Data Collected ...");
}catch(Exception e)
{
e.printStackTrace();
}
}
public List getState() {
return state;
}
#Override
public String execute() throws Exception {
// TODO Auto-generated method stub
setState(this.state);
setStatus(this.status);
return "success";
}
public String showEventDetails(){
System.out.println("Hi.."+eventName);
return SUCCESS;
}
public void setState(List state) {
//implement the application specific logic to
try {
Database database = new Database();
Connection con = database.Get_Connection();
PreparedStatement ps = con
.prepareStatement("SELECT EVENT_ID,EVENT_NAME,COMPANY_NAME,CONTACT_PERSON,CONTACT_NO,EMAIL_ID,EVENT_VENUE,date_format(FROM_DATE,'%d/%m/%Y') as dateAsFrom,date_format(TO_DATE,'%d/%m/%Y') as dateAsTo ,EVENT_TIME FROM EVENT");
ResultSet rs = ps.executeQuery();
dataForBillsJspList = new ArrayList<Event>();
while (rs.next()) {
dataForBillsJspList.add(new Event(rs.getString("EVENT_ID"),rs.getString("EVENT_NAME"),
rs.getString("COMPANY_NAME"),rs.getString("CONTACT_PERSON"),rs.getString("CONTACT_NO"),rs.getString("EMAIL_ID"),rs.getString("EVENT_VENUE"), rs
.getString("dateAsFrom"), rs
.getString("dateAsTo"),rs.getString("EVENT_TIME")));
//System.out.println(rs.getString("EVENT_NAME"));
state.add(rs.getString("EVENT_NAME"));
System.out.println(rs.getString("EVENT_ID"));
}
System.out.println("Data Collected ...");
}catch(Exception e)
{
e.printStackTrace();
}
//Here for displaying the data on UI, we are using few hardcoded values//
}
}
After loading dynamic dropdown list now i am trying to call selected value in action class by S.O.P but it gives null pointer exception. Below is my POJO class:
package com.ca.pojo;
public class Dropdown
{
private String eventState;
private String companyState;
public Dropdown() {
// TODO Auto-generated constructor stub
}
public String getEventState() {
return eventState;
}
public void setEventState(String eventState) {
this.eventState = eventState;
}
public String getCompanyState() {
return companyState;
}
public void setCompanyState(String companyState) {
this.companyState = companyState;
}
}
and below is action class where I am trying to call that selected value by using name attribute :
package com.ca.actions;
import com.ca.pojo.Dropdown;
import com.opensymphony.xwork2.ActionSupport;
public class DropdownAction extends ActionSupport
{
Dropdown dp;
public DropdownAction() {
// TODO Auto-generated constructor stub
}
public Dropdown getDp() {
return dp;
}
public void setDp(Dropdown dp) {
this.dp = dp;
}
#Override
public String execute() throws Exception {
// TODO Auto-generated method stub
System.out.println(dp.getEventState());
return "success";
}
}
struts.xml is properly configured. Now after selecting two values I want to display data in the below table accordingly without any button click but in jsp i have created button just to see whether i am getting the selected value in action class but in actual i want it without any button click.
Well, there is a huge mess here :D
First of all, the NullPointerException is thrown because the values are not sent, and the values are not sent because they're not in the form.
You should enclose them in the form like this for them to be sent to the ActionSelect action:
<s:form action="ActionSelect">
<div class="invoicetext1">Event Name :</div>
<s:select name="dp.eventState"
list="%{state}"
class="billlistbox1"
id="eventName" />
<div>
<s:select name="dp.companyState"
class="billlistbox2"
listKey="companyState"
list="%{status}">
</s:select>
</div>
<div class="invoicetext2">Company Name :</div>
<div class="clear"></div>
</div>
<s:submit value=" Click Here"/>
</s:form>
Solved the mistery, this doesn't solve your problem, though.
You have two main ways to contact actions from a page:
Using a standard submit (as you're doing):
you either submit a form with its content, or call a link by eventually passing parameters in the querystring. This creates a Request, that will contact an action, that will return an entire JSP, that will be loaded in place of the page you're on now.
Using AJAX:
you POST or GET to an action without changing the current page, and the action can return anything, like a JSP snippet, a JSON result, a binary result (through the Struts2 Stream result), etc...
You then can choose what to do with the returned data, for example load it inside a <div> that before was empty, or had different content.
Now your problem is that you're contacting an action that is not the one you're coming from (is not able to re-render the entire JSP you're on) and you're calling it without using AJAX, then whatever the object mapped to the "success" result is (the whole JSP, or a JSP snippet), it will be loaded in place of the JSP you're on, and it will fail.
Since you seem to be quite new to this, I suggest you start with the easy solution (without AJAX), and after being expert with it, the next time try with AJAX.
That said,
avoid putting logic in getters and setters;
avoid calling methods that are not setter as setters (setState, setStatus...);
always make your attributes private;
try giving speaking names to variables: state and status for event states and company states are really confusing; and what about "state" instead of "name" (in jsp and on DB is "name");
consider loading informations like selectbox content in a prepare() method, so they will be available also in case of errors;
you're not closing the connections (and BTW it would be better to use something more evoluted, like Spring JDBC, or better Hibernate, or even better JPA, but for now keep going with the raw queries)
The following is a refactoring of your code to make it achieve the goal. I'll use #Getter and #Setter only for syntactic sugar (they're Lombok annotations, but you keep using your getters and setters, it's just for clarity):
<head>
<script>
$(function(){
$("#event, #company").on('change',function(){
$("#myForm").submit();
});
});
</script>
</head>
<body>
<form id="myForm">
<div>
...
<s:select id="event" name="event" list="events" />
...
<s:select id="company" name="company" list="companies" />
...
</div>
</form>
<div>
...
Table - iterate **dataForBillsJspList** here
...
</div>
</body>
public class RetrieveEvNaCoNaAction extends ActionSupport {
private static final long serialVersionUID = -5418233715172672477L;
#Getter private List<Event> dataForBillsJspList = new ArrayList<Event>();
#Getter private List<String> events = new ArrayList<String>();
#Getter private List<String> companies = new ArrayList<String>();
#Getter #Setter private String event = null;
#Getter #Setter private String company = null;
#Override
public void prepare() throws Exception {
Connection con;
try {
con = new Database().Get_Connection();
// load companies
PreparedStatement ps = con.prepareStatement("SELECT DISTINCT company_name FROM event");
ResultSet rs = ps.executeQuery();
while (rs.next()) { companies.add(rs.getString("company_name")); }
// load events
ps = con.prepareStatement("SELECT DISTINCT event_name FROM event");
rs = ps.executeQuery();
while (rs.next()) { events.add(rs.getString("event_name")); }
} catch(Exception e) {
e.printStackTrace();
} finally {
con.close();
}
}
#Override
public String execute() {
Connection con;
try {
con = new Database().Get_Connection();
// load the table. The first time the table is loaded completely
String sql = "SELECT EVENT_ID, EVENT_NAME, COMPANY_NAME, CONTACT_PERSON, CONTACT_NO, EMAIL_ID, EVENT_VENUE, " +
"date_format(FROM_DATE,'%d/%m/%Y') as dateAsFrom, date_format(TO_DATE,'%d/%m/%Y') as dateAsTo ,EVENT_TIME " +
"FROM event";
String where = "";
// if instead this action has been called from the JSP page,
// the result is filtered on event and company:
if (event!=null && company!=null) {
where = " WHERE event_name = ? AND company_name = ?";
}
// load companies
PreparedStatement ps = con.prepareStatement(sql + where);
if (where.length()>0) {
ps.setString(1,event);
ps.setString(2,company);
}
ResultSet rs = ps.executeQuery();
while (rs.next()) {
dataForBillsJspList.add(new Event(rs.getString("EVENT_ID"),rs.getString("EVENT_NAME"),rs.getString("COMPANY_NAME"),
rs.getString("CONTACT_PERSON"),rs.getString("CONTACT_NO"),rs.getString("EMAIL_ID"),
rs.getString("EVENT_VENUE"), rs.getString("dateAsFrom"), rs.getString("dateAsTo"),
rs.getString("EVENT_TIME")));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
con.close();
}
return SUCCESS;
}
}
It is a kickoff example, but it should work.
The next steps are:
create a POJO with id and description, show the description in the select boxes, but send the id
use header values ("please choose an event"...) and handle in action conditional WHERE (only company, only event, both)
PAGINATION
Good luck
Using Javascript/jQuery you can do this, it depends on what you want to do after reached action class.
If you want to navigate to another page use the code below.
Add onchange event as an attribute to your dropdown,
onchange="customFunction(this.value)"
create customFunction in header part,
function customFunction(selectedValue){
window.location="Action_URL?myValue="+selectedValue;
}
Or if you want to return back the same page use jQuery ajax,
$("#eventName").change(function(e){
var selectedValue = $(this).val();
$.ajax({
type : 'post',
url : 'Action_URL',
data: { myValue: selectedValue},
success : function(data) {
alert(data);
console.log(data);
}
});
});
Hope this helps.