I use displaytag on a list bean: utilisateurBean. I need to add a column on this tab to add a checkbox for selecting an element.
Pb : With the displaytag struts looks for the property choixUtilisateur in the bean and not in the formBean. Is there a way to talk struts/displaytag to map this property in the form? I don't understand the mix of prestenation layer/ business layer that this involves.
I understand that I iterate on the bean and that he looks for the property in. But I did not understand the mapping of the decorator property in the business layer.
My code :
<html:form action="/rechercheUtilisateur"
name="formRechercheUtilisateur"
decorator="org.displaytag.render.DecorateurCheckbox"
type="lan.poujoulat.osac.forms.FormRechercheUtilisateur">
...
<div align="center"><display:table style="width: 100%;"
class="mars" sort="list"
name="formRechercheUtilisateur.listeUtilisateurs"
id="formRechercheUtilisateur.listeUtilisateurs"
decorator="org.displaytag.render.DecorateurCheckbox"
cellspacing="4" cellpadding="2" pagesize="10"
requestURI="rechercheUtilisateur.do" export="true" >
<display:column title="id" property="id" sortable="true"
style="color: black;" headerClass="sortable"></display:column>
...
<display:column media="html" property="choixUtilisateur" title=" "></display:column>
...
</display:table></div>
</html:form>
The DecorateurCheckbox.java to add checkbox to my tab:
public class DecorateurCheckbox extends TableDecorator{
...
public String getChoixUtilisateur()
{
String retour = "";
UtilisateurBean user= (UtilisateurBean) getCurrentRowObject();
int idUser ;
idUser = user.getId();
retour = "<input type='checkbox' name='formRechercheUtilisateur' property='choixUtilisateur' value='"+idUser+"' id='selectedArticle" + idUser + "' />";
return retour;
}
...
}
Error:
/Administration/acces.jsp. Exception : javax.servlet.ServletException:
Error looking up property "choixUtilisateur" in object type
"xxx.UtilisateurBean".
public class DecorateurCheckbox extends TableDecorator{
public String getChoixUtilisateur()
{
String retour = "";
UtilisateurBean user= (UtilisateurBean) getCurrentRowObject();
int idUser ;
idUser = user.getId();
retour = "<input type='checkbox' name='utilisateurModif' property='choixUtilisateur' value='"+idUser+"' id='" + idUser + "' />";
return retour;
}
}
utilisateurModif is the form property and choixUtilisateur is the displaytag property with the decorator :
jsp :
<display:column property="choixUtilisateur" title="modif"></display:column>
Related
I am working on a lightning component that will display a custom, dynamic, list of 'related' records that can be used to display related records in a list on an object that is ALSO a child of the same parent. So, for example, If the Account is the parent record, and custom object 1 and custom object 2 are both children of the account, I want to display the custom object 1 records that are associated with the same account as custom object 2 on the custom object 2 lightning record page. I am using user inputs in the LC canvas and field sets to locate the records and display the columns, respectively.
The component I created works in that it does query and display the records, columns, and field values dynamically. I wanted to also include a clickable link to the custom object 1 records using the 'Name' field. However, I can't seem to dynamically set the typeAttribute of the Name field to display the label of the record. Because I am assigning it as an attribute of the column header, it is only taking the last value in the array.
Is there a way to assign the typeAttribute to the records response, and NOT the column header response?
Here is my code:
Apex Class:
public class DynamicRelatedListController {
#AuraEnabled
public static String fetchParent(String recId, String parentLookup, String objPageName) {
String strSOQL = 'SELECT Id, ' + parentLookup + ' FROM ' + objPageName + ' WHERE Id = \'' + recId + '\' LIMIT 1 ' ;
List <SObject> currentRecord = new List <SObject>(Database.query(strSOQL));
system.debug('Database Result for fetch parent ' + strSOQL);
List <String> parentIds = new List<String>();
for(SObject cr : currentRecord) {
parentIds.add(String.valueOf(cr.get(parentLookup)));
}
String parentId = parentIds[0];
return parentId;
}
#AuraEnabled
public static List < SObject > fetchChildren(String objectName, String criteria, String parentFieldAPIName, String recId, String parentLookup, String objPageName) {
String parentId = fetchParent(recId, parentLookup, objPageName);
// String prefix ='%' + GM_Util.findObjectNameFromRecordIdPrefix(parentId) + '%';
List < SObject > childRecordList = new List < SObject > ();
String strSOQL = 'SELECT Id, ' + parentFieldAPIName + ' FROM ' + objectName + ' WHERE ' + parentFieldAPIName + ' = \'' + parentId + '\'';
if ( String.isNotBlank( criteria ) )
strSOQL += ' ' + criteria;
childRecordList = Database.query(strSOQL);
system.debug('Database Result for fetch children ' + strSOQL);
return childRecordList;
}
#AuraEnabled
public static DataTableDetails fetchRelatedRecs(String recId, String fieldSetName, String criteria, String objectName, String parentFieldAPIName, String objPageName, String parentLookup)
{
DataTableDetails dataTableDtls = new DataTableDetails();
List<GM_Util_Aura.FieldSetMemberWrapperClass> listOfFieldSetMembers = new List<GM_Util_Aura.FieldSetMemberWrapperClass>();
if(fieldSetName != NULL && fieldSetName != ''){
listOfFieldSetMembers = GM_Util_Aura.getFieldSetMemberJSON(objectName, fieldSetName);
}
// List<GM_Util_Aura.FieldSetMemberWrapperClass> listOfFieldSetMembers = GM_Util_Aura.getFieldSetMemberJSON(objectName, fieldSetName);
List<String> WHERE_IN_LIST = new List <String>();
for (SObject crl: fetchChildren(objectName, criteria, parentFieldAPIName, recId, parentLookup, objPageName)) {
WHERE_IN_LIST.add(crl.Id);
}
String SQL = 'SELECT Id ';
if(listOfFieldSetMembers != null && listOfFieldSetMembers.size() > 0){
for(GM_Util_Aura.FieldSetMemberWrapperClass fsmwc : listOfFieldSetMembers){
dataTableDtls.fieldLabelsList.add(fsmwc);
SQL = SQL + ',' + fsmwc.fieldName;
}
}
SQL += ' FROM ' + objectName +' WHERE Id IN : WHERE_IN_LIST' ;
System.debug('final SQL statement (WHERE_IN_LIST): ' + SQL);
dataTableDtls.returnedParentRecords = Database.query(SQL);
System.debug('returned Parent Records are ' + Database.Query(SQL));
// filteredResults = Database.query(SQL);
System.debug('final filtered results are: ' + dataTableDtls);
System.debug('returned field labels are ' + listOfFieldSetMembers);
return dataTableDtls;
}
public class DataTableDetails{
#AuraEnabled
public List<sObject> returnedParentRecords = new List<sObject>();
#AuraEnabled
public List<GM_Util_Aura.FieldSetMemberWrapperClass> fieldLabelsList = new List<GM_Util_Aura.FieldSetMemberWrapperClass>();
}
}
My component helper & cmp code:
({
getDataTable: function(component, event) {
console.log("entered Get Data Table");
var action = component.get("c.fetchRelatedRecs");
action.setParams({
recId: component.get("v.recordId"),
objectName: component.get("v.ObjectAPIName"),
fieldSetName: component.get("v.FieldSetAPIName"),
objPageName: component.get("v.sObjectName"),
parentFieldAPIName: component.get("v.ParentFieldAPIName"),
parentLookup: component.get("v.ParentFieldLookupName"),
criteria: component.get("v.criteria")
});
action.setCallback(this, function(response){
//console.log("this is the fieldSetName " + fieldSetName)
var state = response.getState();
if(state === 'SUCCESS'){
var fieldSetResponse = response.getReturnValue().fieldLabelsList;
var parentRecordsResponse = response.getReturnValue().returnedParentRecords;
console.log("Parent records length " + parentRecordsResponse.length);
console.log("Field Set Length " + fieldSetResponse.length);
console.log("here are the field labels before data transformation " + JSON.stringify(fieldSetResponse));
console.log("Here are all the related records before transformation " + JSON.stringify(parentRecordsResponse));
//this for loop changes all lookup fields to type 'url' for clickable links
for(var i = 0; i < parentRecordsResponse.length; i++ ) {
if(fieldSetResponse[i].fieldName.includes('__r.Name')) {
fieldSetResponse[i].type ='url';
//drop the .Name from the lookup field so that the lightning:datatable can find the field value in the parentRecordsResponse object
fieldSetResponse[i].fieldName = fieldSetResponse[i].fieldName.replace('.Name', '') ;
//this for loop locates the key in the parentRecordsResponse object that matches the lookup field in the fieldSetResponse object.
for(var j = 0; j < parentRecordsResponse.length; j++) {
var arraykeys = Object.keys(parentRecordsResponse[j]);
var arrayvalues = Object.values(parentRecordsResponse[j]);
console.log("Array Keys in iteration "+ arraykeys[j]);
console.log("Array Values " + JSON.stringify(arrayvalues));
//this for loop locates the key in the parentRecordsResponse object that matches the lookup field in the fieldSetResponse object.
for(var h = 0; h <arraykeys.length; h++) {
console.log("Array Keys in iteration h "+ arraykeys[h]);
//fieldSetResponse[i]['typeAttributes'] = {label: arrayvalues[h].Name };
if(fieldSetResponse[i].fieldName === arraykeys[h]){
//assign the'type attributes' to the url field with the Name value of the lookup field
fieldSetResponse[i]['typeAttributes'] = {label: arrayvalues[h]['Name'] };
//transform the nested lookup field object to /recordId for the url
parentRecordsResponse[j][arraykeys[h]] = "/" + arrayvalues[h].Id ;
}
}
}
}
}
console.log("here are the field labels after data transformation " + JSON.stringify(fieldSetResponse));
console.log("Here are all the related records " + JSON.stringify(parentRecordsResponse));
//send the responses back to the controller and set them using the 'v.' keys
component.set("v.columnsHeader", fieldSetResponse);
component.set("v.listofRelatedRecords", parentRecordsResponse);
}
else if (state === 'ERROR'){
console.log('::::::::::::: ERROR :::::::::::::');
}
});
$A.enqueueAction(action);
}
})
<aura:component controller="DynamicRelatedListController" implements="flexipage:availableForRecordHome,force:hasRecordId,force:lightningQuickAction,force:hasSObjectName" access="global">
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
<aura:attribute name="ObjectAPIName" type="String"/>
<aura:attribute name="FieldSetAPIName" type="String"/>
<aura:attribute name="ParentFieldAPIName" type="String"/>
<aura:attribute name="ParentFieldLookupName" type="String"/>
<aura:attribute name="Criteria" type="String"/>
<aura:attribute name="TableName" type="String"/>
<!-- <aura:attribute name="recordId" type="String" /> -->
<aura:attribute name="columnsHeader" type="List"/>
<aura:attribute name="listofRelatedRecords" type="Object"/>
<lightning:card aura:id="lightCard" class="slds-card_boundary" title="{!v.TableName}" iconName="standard:file">
<div style="overflow-x: auto;">
<lightning:datatable data="{!v.listofRelatedRecords}"
columns="{!v.columnsHeader}"
keyField="Id"
hideCheckboxColumn="true"/>
</div>
</lightning:card>
</aura:component>
This is what the end result looks like - note that all of the values ARE different, except for the label of the Name field. The link itself works fine, and navigates to the appropriate record:
I figured it out. At a basic level, this line is missing the attribute of 'fieldName', which takes the API of the field name and applies the value.
So this: fieldSetResponse[i]['typeAttributes'] = {label: arrayvalues[h]['Name'] };
Should be this: fieldSetResponse[i]['typeAttributes'] = {label: fieldName: {API NAME OF FIELD THAT HOLDS THE DISPLAY VALUE} };
Even so, this is not possible to do dynamically because When the fieldName in this case is the lookup field itself, it displays the record Id. I could pass a hard-coded API name, but obviously that would defeat the purpose.
To get around this, I added a generic label (click to view record) and created a formula field on that target object that pulls in the parent record name and added that to my field set.
This is a known issue: https://trailblazer.salesforce.com/ideaView?id=0873A000000lLXYQA2
That could potentially be handled by creating a flattening function (although I haven't tried to implement that yet): https://developer.salesforce.com/forums/?id=9062I000000XtwnQAC
I need to build out a solution to create a search field on the new Case Type Data object in all 3 of the Level fields and populate based on selection.
Similar to SF Global Search I would like to type 2-3 characters in the text search field and it would find the matching text in the Level1-3 fields and when selected the Level 1-3 field would populate.
This is the apex class
public class PickListHandler {
#AuraEnabled
public static List<String> getLevel1(){
List<String> tempLst1 = new List<String>();
for(AggregateResult ar : [select Level_1__c,COUNT(id) from Case_Type_Data__c group by Level_1__c])
{
tempLst1.add(''+ar.get('Level_1__c'));
}
return tempLst1;
}
#AuraEnabled
public static List<String> getLevel2(string strName){
List<String> tempLst2 = new List<String>();
for(AggregateResult ar : [select Level_2__c,COUNT(id) from Case_Type_Data__c where Level_1__c=:strName group by Level_2__c])
{
tempLst2.add(''+ar.get('Level_2__c'));
}
return tempLst2;
}
#AuraEnabled
public static List<String> getLevel3(string strName1,string strName2){
List<String> tempLst3 = new List<String>();
for(AggregateResult ar : [select Level_3__c,COUNT(id) from Case_Type_Data__c where Level_1__c=:strName1 and Level_2__c=:strName2 group by Level_3__c])
{
tempLst3.add(''+ar.get('Level_3__c'));
}
return tempLst3;
}
#AuraEnabled
public static String savecasetype(string level1,string level2,string level3,string id){
string strMsg='successfull';
try{
ERT_Case_Type__c obj=new ERT_Case_Type__c();
Obj.Case__c = id;
System.debug('CASE = '+ Obj.Case__c);
Obj.Level_1__c=level1;
System.debug('Level1 = '+ Obj.Level_1__c);
Obj.Level_2__c=level2;
System.debug('Level2 = '+ Obj.Level_2__c);
Obj.Level_3__c=level3;
System.debug('Level3 = '+ Obj.Level_3__c);
Insert obj;
}
catch(Exception ex){
strMsg='error';
}
return strMsg;
}
}
This is the Picklist handler component
<aura:component controller="PickListHandler" implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global" >
<!-- Actions-->
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
<!-- variable-->
<aura:attribute name="lstLevel1" type="String[]" />
<aura:attribute name="lstLevel2" type="String[]" />
<aura:attribute name="lstL3" type="String[]" />
<span> Level 1</span>
<ui:inputSelect aura:id="ddLevel1" change="{!c.getLvl1}">
<ui:inputSelectOption label="-Select-" value="true"/>
<aura:iteration items="{!v.lstLevel1}" var="value">
<ui:inputSelectOption label="{!value}" text="{!value}" />
</aura:iteration>
</ui:inputSelect>
<span>Level 2</span>
<ui:inputSelect aura:id="ddLevel2" change="{!c.getSelectedValue}">
<ui:inputSelectOption label="-Select-" value="true"/>
<aura:iteration items="{!v.lstLevel2}" var="value">
<ui:inputSelectOption label="{!value}" text="{!value}" />
</aura:iteration>
</ui:inputSelect>
<span>Level 3</span>
<ui:inputSelect aura:id="ddLevel3" >
<ui:inputSelectOption label="-Select-" value="true"/>
<aura:iteration items="{!v.lstL3}" var="value">
<ui:inputSelectOption label="{!value}" text="{!value}" />
</aura:iteration>
</ui:inputSelect>
<lightning:button variant="brand" label="Save" onclick="{!c.onConfirm}" />
</aura:component>
Regards,
Carolyn
You're asking for a lot, we wouldn't have your custom object. And this is old code, ui:inputSelect is deprecated for 1 year now. I'll try to help a bit but the whole thing needs your work too. And examples we can reproduce easily.
I'm going to cheat and use Philippe Ozil's ready component for the lookup/autocomplete thing.
It means you'd have to save LookupSearchResult class, the whole aura component and 2 aura events in your org before reading below. That's some prep work but it's battle-tested :)
Apex class
public with sharing class Stack64129038 {
#AuraEnabled(cacheable=true)
public static List<LookupSearchResult> search(String searchTerm, List<String> selectedIds){
if(String.isBlank(searchTerm) || searchTerm.length() < 2){
return null;
}
String t = '%' + searchTerm + '%'; // decide how you want to search, "starts with", "includes" or what
List<Case_Type_Data__c> records = [SELECT Id, Name, Level_1__c, Level_2__c, Level_3__c
FROM Case_Type_Data__c
WHERE Level_1__c LIKE :t OR Level_2__c LIKE :t OR Level_3__c LIKE :t
ORDER BY Level_1__c, Level_2__c, Level_3__c
LIMIT 20];
/* You could also experiment with SOSL?
records = [FIND :('*' + searchTerm + '*') IN ALL FIELDS
RETURNING Case_Type_Data__c(Id, Name, Level_1__c, Level_2__c, Level_3__c)][0];
*/
List<LookupSearchResult> results = new List<LookupSearchResult>();
for(Case_Type_Data__c ctd : records){
results.add(new LookupSearchResult(ctd.Id, 'Case_Type_Data__c', 'standard:case_wrap_up', ctd.Name,
String.join(new List<String>{ctd.Level_1__c , ctd.Level_2__c, ctd.Level_3__c}, '; ')
));
}
return results;
}
}
Aura component (html part)
<aura:component implements="force:hasRecordId,force:appHostable,flexipage:availableForAllPageTypes,force:lightningQuickAction" access="global" controller="Stack64129038">
<aura:attribute access="private" type="List" name="selection" default="[]"/>
<aura:attribute access="private" type="List" name="errors" default="[]"/>
<lightning:card title="New Case Type">
<lightning:recordEditForm aura:id="myForm" objectApiName="ERT_Case_Type__c" onsubmit="{!c.onSubmit}" onsuccess="{!c.onSuccess}">
<lightning:messages />
<c:Lookup selection="{!v.selection}" onSearch="{!c.lookupSearch}" onSelection="{!c.useSelected}" errors="{!v.errors}" label="Search" placeholder="Search Case Types Data"/>
<lightning:inputField aura:id="Level_1__c" fieldName="Level_1__c" />
<lightning:inputField aura:id="Level_2__c" fieldName="Level_2__c" />
<lightning:inputField aura:id="Level_3__c" fieldName="Level_3__c" />
<lightning:button class="slds-m-top_small" variant="brand" type="submit" name="save" label="Save" />
</lightning:recordEditForm>
</lightning:card>
</aura:component>
Aura component - JS controller part
({
lookupSearch : function(component, event, helper) {
// Get the lookup component that fired the search event
const lookupComponent = event.getSource();
const serverSearchAction = component.get('c.search');
lookupComponent.search(serverSearchAction);
},
useSelected: function(component, event, helper) {
const selection = component.get('v.selection');
const errors = component.get('v.errors');
if (selection.length) {
if(errors.length){ // Clear errors, if any
component.set('v.errors', []);
}
let levels = selection[0].subtitle.split('; ');
component.find('Level_1__c').set('v.value', levels[0]);
component.find('Level_2__c').set('v.value', levels[1]);
component.find('Level_3__c').set('v.value', levels[2]);
}
},
onSubmit: function(component, event, helper) {
debugger;
event.preventDefault(); // stop the form from submitting
var fields = event.getParam('fields');
fields.Case__c = component.get('v.recordId'); // link to "this" Case
component.find('myForm').submit(fields);
},
onSuccess: function(component, event, helper){
var toastEvent = $A.get("e.force:showToast");
toastEvent.setParams({
"title": "Success!",
"message": "Case Type saved OK, refreshing",
"type": "success"
});
toastEvent.fire();
$A.get('e.force:refreshView').fire(); // reload page
}
})
Table :
this is table name
Requirement :
Using RestAPI call populate unique cateID, categoryName , but I am getting the whole record.
Table
Table Data which I am using
Code Description :
Repository :
#Repository
public interface CategoryRepository extends JpaRepository<xCategory,Integer>
{
// #Query("SELECT DISTINCT a.catID,a.categoryName FROM ccCategory a order by categoryName asc")
#Query("SELECT DISTINCT a.catID, a.categoryName FROM xCategory a order by categoryName asc")
List<ccCategory> getCategoryName();
}
Rest Controller:
#RestController
#CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
public class HomeResource {
private final Logger log = LoggerFactory.getLogger(HomeResource.class);
#Autowired
CategoryRepository categoryRepository;
#GetMapping("/getAllCategory")
public List<ccCategory> getAllCategory() {
// public List<String> getAllCategory() {
System.out.println("***** Call : API getAllCategory() ******");
List<ccCategory> cCategory = categoryRepository.findAll();
return cCategory;
}
Angular Code :
<label class="control-label">Category: </label>
<select [(ngModel)]="listAllCategory" name="xxcategory" class="form-control" required>
<option *ngFor="let xxcategory of listAllCategory" [value]="xxcategory.catID">
{{xxcategory.categoryName}}
</option>
</select>
Problem :
Drop Down populating all the table value but I want only the UNIQUE value like only one time catID , categoryName.
You have to add a variable to keep the selected element in your select and then change your [(ngModel)]="listAllCategory" with [(ngModel)]="selectedCategory"
I'm building app using angularjs and spring boot framework.
I post a normal form to rest web api, and it works. But i don't know how to post a form data with nested entity (like foreign key in another table).
What I tried is:
JS:
vm.product = {
id: '',
name: '',
price: '',
detail: '',
brand:{
brand_id: ''
},
subcategory:{
subcategory_id: ''
}
}
vm.submitForm = function () {
$http.post("http://localhost:8080/api/products/", vm.product)
.then(
function (response) {
deferred.resolve(response.data);
},
function (errResponse) {
console.error('Error while creating Product: ' + errResponse.data.errorMessage);
deferred.reject(errResponse);
}
);
}
Form
<form class="forms-sample" ng-submit="products.submitForm()">
<div class="form-group">
<label for="exampleInputName1">Name</label>
<input type="text" class="form-control" id="exampleInputName1" ng-model="products.product.name"
placeholder="Name">
</div>
<div class="form-group">
<label for="exampleInputPassword4">Price</label>
<input type="number" class="form-control" id="exampleInputPassword4" ng-model="products.product.price"
placeholder="Price">
</div>
<div class="form-group">
<label for="exampleTextarea1">Detail</label>
<textarea class="form-control" id="exampleTextarea1" rows="2" ng-model="products.product.detail"></textarea>
</div>
<div class="form-group">
<label for="exampleTextarea1">Brand Id</label>
<select ng-model="products.product.brand.brand_id" class="form-control" id="exampleFormControlSelect2">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select>
</div>
<div class="form-group">
<label for="exampleTextarea1">Subcategory Id</label>
<select ng-model="products.product.subcategory.subcategory_id" class="form-control" id="exampleFormControlSelect2">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select>
</div>
<button type="submit" class="btn btn-success mr-2">Submit</button>
<button class="btn btn-light">Cancel</button>
</form>
Entity:
#Entity
#Table(name = "product")
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
//----------------------------------------------------------------------
// ENTITY PRIMARY KEY
//----------------------------------------------------------------------
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
//----------------------------------------------------------------------
// ENTITY DATA FIELDS
//----------------------------------------------------------------------
#Column(name = "detail", length = 2147483647)
private String detail;
private String name;
#Column(name = "price", nullable = false)
private Double price;
// Attribute "brandId" is a link
// Attribute "subcategoryId" is a link
//----------------------------------------------------------------------
// ENTITY LINKS ( RELATIONSHIP )
//----------------------------------------------------------------------
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "subcategory_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonBackReference(value = "subcategory _id")
private Subcategory subcategory;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "brand_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonBackReference(value = "brand _id")
private Brand brand;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "product")
#JsonManagedReference(value = "product _id")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
private List<Review> listOfReview;
// getters and setters
//----------------------------------------------------------------------
// toString METHOD
//----------------------------------------------------------------------
#Override
public String toString() {
return "Product{" +
"id=" + id +
", detail='" + detail + '\'' +
", image1='" + image1 + '\'' +
", image2='" + image2 + '\'' +
", image3='" + image3 + '\'' +
", name='" + name + '\'' +
", price=" + price +
", subcategory=" + subcategory +
", brand=" + brand +
'}';
}
}
WEBAPI
#CrossOrigin
#PostMapping("/api/products")
public Product createProduct(#RequestBody Product product) {
System.out.println("Product: " + product);
System.out.println("Subcategory: " + product.getSubcategory());
Product product1 = productRepository.save(product);
return product1;
}
It seems that subcategory_id and brand_id can't be parsed.
In console, product is printed as following:
Product: Product{id=null, detail='asdg', image1='null', image2='null', image3='null', name='dfgfsg', price=3.0, subcategory=null|null, brand=null|null}
So how can I post a form with foreign key like this app? I search a lot but can't find solution.
Thanks
It seems that you are trying to save Product and its children in one go.
You would need two additional things to achieve that:
1) Turn on PERSIST cascading:
#ManyToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.PERSIST)
...
private SubCategory subcategory;
2) If the Subcategory has a #OneToMany association to Product, then you would need to set both sides of relationship:
public Product createProduct(#RequestBody Product product) {
Subcategory subCat: product.product.getSubcategory();
subCat.getProducts().add(product);
Product product1 = productRepository.save(product);
return product1;
}
You dont need that of course if its only mapped in Product solely.
I had a problem on printing array of data in JSP, heres what happend.
I created a POJO called: popArayCustOrd
public class popAryCustOrd {
public String prodkey,descrp,strgth,stkunt;
double rprice;
int quantity;
popAryCustOrd(String prodkey,String descrp,int quantity,Double rprice,String stkunt,String strgth){
this.prodkey = prodkey;
this.descrp = descrp;
this.quantity = quantity;
this.rprice = rprice;
this.stkunt = stkunt;
this.strgth = strgth;
}
public void setProdkey(String prodkey){
this.prodkey = prodkey;
}
public String getProdkey(){
return(this.prodkey);
}
public void setDescrp(String descrp){
this.descrp = descrp;
}
public String getDescrp(){
return(this.descrp);
}
public void setQuantity(int quantity){
this.quantity = quantity;
}
public int getQuantity(){
return(this.quantity);
}
public void setRprice(double rprice){
this.rprice = rprice;
}
public double getRprice(){
return(this.rprice);
}
public void setStkunt(String stkunt){
this.stkunt = stkunt;
}
public String getStkunt(){
return(this.stkunt);
}
public void setStrgth(String strgth){
this.strgth = strgth;
}
public String getStrgth(){
return(this.strgth);
}
}
and in my servlet file called seekprod.java I assigned data coming from the database within a method....
connx.rs.beforeFirst();
while(connx.rs.next()){
popAryCustOrd[] prodList = new popAryCustOrd[]{new popAryCustOrd(connx.rs.getString("prodkey"),connx.rs.getString("descrp"),connx.rs.getInt("quantity"),connx.rs.getDouble("retailp"),connx.rs.getString("stkunit"),connx.rs.getString("strength"))};
request.setAttribute("prodList", prodList);
}
RequestDispatcher dispatcher = request.getRequestDispatcher("preOrdFrm.jsp? inKey="+this.inKey+"&transkey=drugs");
dispatcher.forward(request, response);
.......
and my JSP to access the data is.....
<c:forEach items="${prodList}" var="paramx" >
<tr>
<td>${paramx.prodkey}</td>
<td style="text-align: center; word-wrap: break-word; word-break:break-all; text-overflow: ellipsis;overflow:hidden;white-space: normal; white-space: -webkit-pre-wrap;">${paramx.descrp}</td>
<td>${paramx.stkunt}</td>
<td>${paramx.strgth}</td>
<td>${paramx.rprice}</td>
<td>${paramx.quantity}</td>
<td><input type="hidden" name="agentId" value="<%=uID %>">
<input type="hidden" name="pcode" value=${paramx.prodkey}>
<input type="hidden" name="inKey" value=${param.inKey}>
<input type="hidden" name="transKey" value="sveOrd">
<input style="font-size:50px; height:55px; width:100px" type="number" name="desqty" min="1" required="" value="1"/></td>
<td><input style="font-size:20px; height:55px; width:100px" type="submit" name="transact" value="Save"/></td>
</tr>
</c:forEach>
eventually it works but I got only one result instead of three records from the database table, my syntax in sql is correct and i checked it many times and compared with the result. I dont know where part of my code to fix. Im very much glad if you could help me .?
while(connx.rs.next()){
popAryCustOrd[] prodList = new popAryCustOrd[]{new
popAryCustOrd(connx.rs.getString("prodkey"),connx.rs.getString("descrp"),connx.rs.getInt("quantity"),connx.rs.getDouble("retailp"),connx.rs.getString("stkunit"),connx.rs.getString("strength"))};
request.setAttribute("prodList", prodList);
}
think about this code it sets and then resets prodList attribute in the request object with every loop execution, so your jsp will recieve only the last value set to prodList.
It would be better to initialize an ArrayList outside the loop and add values to it and then after the loop use that list to set the attribute prodList in request object.