When trying to edit the cell, method not found exception is thrown. I tried using an ajaxBehaviourEvent, but it is throwing ClassCastException: Sheet can not be cast to Sheet
//view
<p:ajax listener="#{dataListView.cellEditEvent}" process=":form:sheet" update=":form:sheet" >
</p:ajax>
// method
public void cellEditEvent(SheetEvent event) {
org.primefaces.extensions.component.sheet.Sheet sheet = event.getSheet();
List<SheetUpdate> updates = sheet.getUpdates();
HashSet<Sample> processed = new HashSet<Sample>();
int rowUpdates = 0;
for (SheetUpdate update : updates) {
Sample asset = (Sample) update.getRowData();
if (processed.contains(asset))
continue;
entityManager.merge(asset);
System.out.println("Asset " + asset.getEmail() + " updated.");
rowUpdates++;
showSampleData();
}
sheet.commitUpdates();
}
Using PrimeFaces 6.2 and PrimeFacesExtension 6.2.3 and Seam 2.3
Related
I have added a field to the Prepare Replenishment form that needs to be updated when a user selects a row in the Replenishment Item grid. How do I access the field. I know it is in the INReplenishmentFilterExt but I can't figure out how to get access to the extension.
Edit #1: I am able to get the value of the field but it does not update on the screen when I use cache.SetValue. I am trying to update this filter extension field from inside of the Selected event handler.
protected void INReplenishmentItem_Selected_FieldUpdating(PXCache cache, PXFieldUpdatingEventArgs e)
{
var row = (INReplenishmentItem)e.Row;
if (row == null)
return;
INReplenishmentFilter filter = Base.Filter.Current;
INReplenishmentFilterExt filterExt = PXCache<INReplenishmentFilter>.GetExtension<INReplenishmentFilterExt>(filter);
decimal poAmount = filterExt.UsrPOAmount.HasValue ? filterExt.UsrPOAmount.Value : 0;
decimal lastPrice = pvi.LastPrice.HasValue ? pvi.LastPrice.Value : 0;
decimal newPOAmount = poAmount + lastPrice;
cache.SetValue<INReplenishmentFilterExt.usrPOAmount>(filterExt, newPOAmount);
}
You cannot set the value of the Filter using the Cache of INReplenishmentItem.
I have edited my answer, the code below should work.
//Always use virtual methods for Event Handlers
protected virtual void INReplenishmentItem_Selected_FieldUpdating(PXCache sender, PXFieldUpdatingEventArgs e)
{
//Try not to use vars. Especially when you know the Type of the object
INReplenishmentItem row = e.Row as INReplenishmentItem;
if (row != null)
{
INReplenishmentFilter filter = Base.Filter.Current;
INReplenishmentFilterExt filterExt = PXCache<INReplenishmentFilter>.GetExtension<INReplenishmentFilterExt>(filter);
decimal poAmount = filterExt.UsrPOAmount ?? 0;
decimal lastPrice = pvi.LastPrice ?? 0;//Not sure what pvi is
decimal newPOAmount = poAmount + lastPrice;
//"sender" is the cache that specifically stores the datatype of row
//Therefor you cannot use it to update records of a different datatype
//You also should not pass an Extension into the argument that should be the row object you are trying to update
Base.Filter.Cache.SetValueExt<INReplenishmentFilterExt.usrPOAmount>(filter, newPOAmount);
}
}
How to display popup exceptions instead of the one with a red dot on the row for the line items? I was able to have them in RowInserting for a little bit but after a series of code changes I get the red dot one instead. It even did not create a new row as I wanted but now it does. RowInserting event:
protected virtual void SOLine_RowInserting(PXCache sender, PXRowInsertingEventArgs e)
{
var listMissingOEdesc = new List<int>();
var select = Base.Transactions.Select();
foreach (SOLine row in select)
{
var isOEDesc = IsOEDescEnabled(sender, row);
var rowExt = PXCache<SOLine>.GetExtension<SOLineExt>(row);
if (isOEDesc == true)
if (rowExt.UsrOedesc == null)
listMissingOEdesc.Add(row.SortOrder.Value);
}
if (listMissingOEdesc.Count > 0)
{
throw new PXException("Line items with sort order {0} do not have OE Desc filled out. Cannot add a new line.", string.Join(", ", listMissingOEdesc));
}
else
Base.Actions.PressSave();
}
Thanks!
There is no easy way, if any at all, to display popup exception and prevent the grid from inserting a new row. The way the framework is designed, PXGrid first inserts a new row on the webpage. After that PXGrid sends a callback to the application server either requesting default field values for the new row (if PXGrid's Mode has InitNewRow="True") or sends all values captured from the webpage to the application server, so the new row can be inserted in the PXCache. Whenever an event handler, on the field or row level, gets invoked, the new row will still be visible to the user on the web page. Even if you invoke Ask method on the Transactions data view within one of the event handlers, the new row won't disappear from the webpage.
With all that said, the best and probably the only way to display popup exception and prevent the grid from inserting a new row is by replacing the standard Add New Row button on PXGrid with a custom action, which will first run the validation and display popup exception, if necessary. Otherwise, a new row will be inserted into PXGrid. It's also required to enable or disable the custom NewSOTran action based on the state of the standard PXGrid's Insert button.
public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
public void SOOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
NewSOTran.SetEnabled(Base.Transactions.AllowInsert);
}
public PXAction<SOOrder> NewSOTran;
[PXButton(CommitChanges = true)]
[PXUIField]
protected void newSOTran()
{
var listMissingOEdesc = new List<SOLine>();
var select = Base.Transactions.Select();
foreach (SOLine row in select)
{
var isOEDesc = !string.IsNullOrEmpty(row.TranDesc);
if (isOEDesc == true)
listMissingOEdesc.Add(row);
}
if (listMissingOEdesc.Count > 0)
{
throw new PXException("Cannot add a new line.");
}
var newTran = Base.Transactions.Insert();
Base.Transactions.Cache.ActiveRow = newTran;
}
}
In Aspx there will required 3 major chages:
SyncPositionWithGraph property set to True for PXGrid:
<px:PXGrid ID="grid" runat="server" DataSourceID="ds" Width="100%" TabIndex="100"
SkinID="DetailsInTab" StatusField="Availability" SyncPosition="True" Height="473px"
SyncPositionWithGraph="True" >
the standard AddNew action must be replaced by a custom NewSOTran action:
<ActionBar>
<Actions>
<AddNew ToolBarVisible ="False" />
</Actions>
<CustomItems>
<px:PXToolBarButton CommandName="NewSOTran" CommandSourceID="ds"
DisplayStyle="Image">
<Images Normal="main#AddNew" />
<ActionBar GroupIndex="0" Order="2" />
</px:PXToolBarButton>
...
</CustomItems>
</ActionBar>
AllowAddNew property set to false in the Mode section of PXGrid to prevent the standart Insert button from execution when users use keyboard shortcuts or double-click on PXGrid:
<Mode InitNewRow = "True" AllowFormEdit="True" AllowUpload="True" AllowDragRows="true"
AllowAddNew="false" />
To select new records’ first cell and switch it to the edit mode (unless the first cell is read-only), it's also required to subscribe to the Initialize and ToolsButtonClick client events of PXGrid:
<ClientEvents Initialize="initTransactionsGrid"
ToolsButtonClick="transactionsGriduttonClick" />
and define the following JavaScript functions:
var isInitEvents = false;
function initTransactionsGrid(a, b) {
if (isInitEvents) return;
isInitEvents = true;
a.events.addEventHandler("afterRepaint", editNewSOTran);
}
function editNewSOTran() {
if (lastActiveRowIndex != null) {
var grid = px_alls["grid"];
if (grid.activeRow) {
var activeRowIndex = grid.rows.indexOf(grid.activeRow);
if (activeRowIndex != lastActiveRowIndex) {
grid.activeRow.activateCell(0, false);
grid.beginEdit();
}
}
lastActiveRowIndex = null;
}
}
var lastActiveRowIndex;
function transactionsGriduttonClick(sender, args) {
if (args.button && args.button.commandName == "NewSOTran") {
if (sender.activeRow)
lastActiveRowIndex = sender.rows.indexOf(sender.activeRow);
else
lastActiveRowIndex = -1;
return;
}
lastActiveRowIndex = null;
}
To package custom JavaScript code into customization, in Layout Editor you can drag and drop a Java Script element from the Add Controls tab and copy your entire JavaScript code into the Script property.
I am working on a Webapp using PrimeFaces. I am very close to a solution, but am stuck with trying to update the chart as new data is calculated.
I have 3 tabs: Inputs, Outputs & Charts.
On the Inputs Tab, I have textboxes and a Submit button.
On the Outputs Tab, I have a datachart to display the data that is calculated after inputs are entered and submit is clicked. I have verified that data is populated correctly.
On the Charts Tab, I have a chart (will be multiple later) that is to display data from the calculation as well.
Here is my relevant code:
public void createNewChart() {
FileInputStream fis = null;
try {
//Graphic Text
BufferedImage bufferedImg = new BufferedImage(100, 25, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bufferedImg.createGraphics();
g2.drawString("This is a text", 0, 10);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(bufferedImg, "png", os);
graphicText = new DefaultStreamedContent(new ByteArrayInputStream(os.toByteArray()), "image/png");
//Chart
File chartFile = new File("C:\\Desktop\\Temp", "Chart" + Math.round(Math.random() * 1000000) + ".png");
chartData = calculateValuesServlet.getChartData();
calculateDataSets();
XYSeriesCollection xyDataset = new XYSeriesCollection();
xyDataset.addSeries(minumumLine);
xyDataset.addSeries(maximumLine);
xyDataset.addSeries(optimumLine);
xyDataset.addSeries(ratingPoint);
chart = ChartFactory.createXYLineChart("Chart Title", xAxis.getAxisLabel(), yAxis.getAxisLabel(), xyDataset, PlotOrientation.VERTICAL, true, false, false);
fixRenderings();
ChartUtilities.saveChartAsPNG(chartFile, chart, 375, 300);
fis = new FileInputStream(chartFile);
chartContent = new DefaultStreamedContent(fis, "image/png");
calculateValuesServlet.setNewChartNeeded(false);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (IOException ex) {
Logger.getLogger(DataChart.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Also, in my index.html:
<p:tab title="Charts">
<h:panelGrid columns="2" cellpadding="10">
<p:graphicImage id="outputChart1" value="#{dataChart.chartContent}" />
</h:panelGrid>
</p:tab>
And for completeness, this is from DataChart.java:
public StreamedContent getChartContent() {
if (chartData != null && !chartData.isEmpty() && calculateValuesServlet.isNewChartNeeded()) {
createNewChart();
}
return chartContent;
}
I have started saving the charts to Desktop\Temp so that I can view the charts. The ones that are created in my Temp folder are correct, but the one that appears on the webapp is not. I also tried setting cache="FALSE" in the graphicImage, but then I get a broken image icon instead of the graph.
I realize this tells me that the webapp is not getting that latest image, but why?
I'm facing problem on image not refresh too.
Try to change the scope to #RequestScoped and add in cache="false" on p:graphicImage
I use Unit of Work and Repository patterns in my software.
There is a dataGridView on form and it gets data from next way:
acceptedBonusesGrid.DataSource = _unitOfWork.DocumentRepository.GetDocumentsInfo();
GetDocumentsInfo is in DocumentRepository. GetDocumentsInfoes - is complex view with joins:
public IQueryable<GetDocumentsInfo> GetDocumentsInfo()
{
return _context.GetDocumentsInfoes;
}
When user double-clicks on record, it's form for editing this record appears. I send unit of work to form:
CorrectionAcceptedForm corrForm = new CorrectionAcceptedForm(_unitOfWork, docNum);
Form opens and link to unit of work is in use:
public CorrectionAcceptedForm(UnitOfWork unitOfWork, int docNum)
{
InitializeComponent();
_unitOfWork = unitOfWork;
_documentData = _unitOfWork.DocumentRepository.GetById(docNum);
AssignValues();
}
User makes changes in the record and saves changes:
private void SaveBill(int billId)
{
if (ValidateChildren())
{
SaveSupplierAddress();
Bill billData = _documentData.Bills.FirstOrDefault(bill => bill.BillId == billId);
if (billData != null)
{
billData.Description = descriptionTextbox.Text;
billData.Price = Convert.ToDecimal(priceTextbox.Text.Replace('.', ','));
_unitOfWork.Save();
}
}
}
When this correction form closes, then datagrid on main form reloads:
acceptedBonusesGrid.DataSource = null;
acceptedBonusesGrid.Columns.Clear();
acceptedBonusesGrid.DataSource = _unitOfWork.DocumentRepository.GetDocumentsInfo();
But after reload - all rows in datagrid are old, that was before making changes.
What is the problem?
After 3 months I have discovered problem.
GetDocumentsInfo() has to be like this:
public IQueryable<GetDocumentsInfo> GetDocumentsInfo()
{
_context.GetDocumentsInfoes.MergeOption = MergeOption.OverwriteChanges;
return _context.GetDocumentsInfoes;
}
Now my DataGrid updates when I make changes in child form.
I have created a view that shows lost connection messages to users which pops over the current view. I want to update the view periodically based on connection status changes.
I can properly get the view and change the text of a label (verified with WriteLines), but nothing changes on the actual display. I even tried removing the view and readding it and calling SetNeedsDisplay, but nothing seems to help.
I have a global variable called OverView:
public static UIView OverView;
I create the label subview, add it to the overview and pop the overview in front of the current view:
UILabel labelTitle = new UILabel();
labelTitle.Text = title;
UIView labelTitleView = (UIView) labelTitle;
labelTitleView.Tag = 5000;
OverView.AddSubview(labelTitleView);
curView.InsertSubviewAbove(OverView, curView);
curView.BringSubviewToFront(OverView);
And then at a later time, I try to modify it like this from another function:
if ((OverView != null) && (OverView.Subviews != null))
{
for (int i = 0; i < OverView.Subviews.Length; i++)
{
WriteToConsole("Type: " + OverView.Subviews[i].GetType());
if (OverView.Subviews[i] is UILabel)
{
WriteToConsole("Found Label with Tag: " + ((UILabel)(OverView.Subviews[i])).Tag + " Text: " + ((UILabel)(OverView.Subviews[i])).Text);
if (((UILabel)(OverView.Subviews[i])).Tag == 5000)
{
WriteToConsole("Setting subview Title to: " + lostConnectionTitle);
lock (overViewLocker)
{
appReference.InvokeOnMainThread(delegate
{
UILabel tempLabel = ((UILabel)(OverView.Subviews[i]));
tempLabel.Text = lostConnectionTitle;
OverView.Subviews[i].RemoveFromSuperview();
OverView.AddSubview(tempLabel);
OverView.BringSubviewToFront(tempLabel);
OverView.SetNeedsLayout();
OverView.SetNeedsDisplay();
WriteToConsole("SetNeedsDisplay");
});
}
}
}
}
}
Have you tried to use delegate methods on your label, and change their value when events occur ?
For example, if your event is clicking on a button, you should have something like that:
yourLabel.Text = "Init";
buttonExample.TouchUpInside += (sender, e) => {
yourLabel.Text = "I touched my button";
};
When your View loads, you'll see "Init" and your button and once you click on it, the label text changed.
Xamarin has some explanation about events and delegate methods here.
I hope that helped.