I'm using two tables, the first one contains "Teams", the second one "Team members" and is populating based on the first table selection. I'm also showing various stats depending on the selection, be it a team or a specific member. If no member is selected, team stats are showed, otherwise member stats are showed.
I'm using ItemChangeListeners on the tables to redraw the stats, but this prevents me to click on an already selected team to "deselect" a selected member from that team, since no event is triggered in that circumstance. As a solution I'm also using a ClickListener on the Team table, but it seems to work only if I click on the word (instead of working on the whole cell).
teamsTable.setClickListener("name", new Table.CellClickListener() {
#Override
public void onClick(Entity item, String columnId) {
if (teamsDs.getItem() == item) {
teamsDs.setItem(null);
teamsDs.setItem((Team) item);
} else {
teamsDs.setItem((Team) item);
teamsTable.setSelected((Team) item);
}
}
});
Is there a better way to catch a click on a table cell? Or is there a better way to approach the problem altogether?
Since CUBA Table is a wrapper of Vaadin table you can use ItemClickListener from Vaadin with CUBA table:
public class DemoScreen extends AbstractWindow {
#Inject
private Table<User> usersTable;
#Override
public void init(Map<String, Object> params) {
super.init(params);
com.vaadin.ui.Table vTable = usersTable.unwrap(com.vaadin.ui.Table.class);
vTable.addItemClickListener((ItemClickEvent.ItemClickListener) event ->
showNotification("Item " + event.getItemId())
);
}
}
It will be fired each time you click on a table cell.
In my current project I would like to be able to create new objects when searching for a reference object. This happens in several places of the application.
For example, let's assume we have a City Entity and a Country Entity. The City entity has a mandatory reference to the Country entity.
In my use case, I would like to create a new City. When I do this, I will have to assign a Country to the new City. When I click on the lookup icon, I get the selection dialog with all existent countries. But if I don't have the Country I want, I have to abort the operation, get back to the countries list and create the new one I'd like to assign to my new city.
Would it be possible to create that new Country from the selection dialog with all countries?
If it is possible, is the country being added to the list right after it has been created?
Would it be possible to one define a range for the countries list? For example, showing only countries in Europe, if the user is in Europe.
I could imagine, that this would be a lot to ask from the framework. But I am just giving a shot and perhaps also giving a new feature idea, which would be nice to have.
Customization of the LOV dialog :
You can easily customize the LOV dialog by creating your own class of the LOV action that is installed next to the reference fields.
Adding a new action in the dialog (the create action) :
public class LovActionWithCreate<E, F, G> extends LovAction<E, F, G> {
private IDisplayableAction createAction;
#Override
protected void feedContextWithDialog(IReferencePropertyDescriptor<IComponent> erqDescriptor,
IQueryComponent queryComponent, IView<E> lovView, IActionHandler actionHandler,
Map<String, Object> context) {
super.feedContextWithDialog(erqDescriptor, queryComponent, lovView, actionHandler, context);
List<IDisplayableAction> defaultLovDialogActions = (List<IDisplayableAction>) context.get(
ModalDialogAction.DIALOG_ACTIONS);
defaultLovDialogActions.add(1, getCreateAction());
}
/**
* Gets create action.
*
* #return the create action
*/
protected IDisplayableAction getCreateAction() {
return createAction;
}
/**
* Sets create action.
*
* #param createAction
* the create action
*/
public void setCreateAction(IDisplayableAction createAction) {
this.createAction = createAction;
}
}
The key point is to override the feedContextWithDialog method in order to install the new action into the dialog.
Next step is to install your new LOV action. You can either do it globally for whole application or per reference view :
replacing the LOV action globally is just a matter of declaring an action named 'lovAction' into your application frontend.groovy, i.e. :
action('lovAction', parent: 'lovActionBase', class:'test.LovActionWithCreate',
custom: [createAction_ref:'theCreateAction']
)
replacing the LOV action on a certain reference field in a form can be done by using the referencePropertyView (in a form or in a table) and its 'lovAction' property, e.g. :
action('lovActionWithCreate', parent: 'lovActionBase', class:'test.LovActionWithCreate',
custom: [createAction_ref:'theCreateAction']
)
form('ACertainForm'){
fields {
...
referencePropertyView name:'country', lovAction:'lovActionWithCreate'
...
}
}
Creating an entity in the LOV dialog :
In the next step, we create the action that will be responsible for opening an extra dialog in order to create the new entity, persist it and, if successful, add it to the LOV result view. This is a little more complicated but not that much.
First of all, we have to open a new dialog.
For doing this, we will inherit the built-in EditComponentAction. The goal of this action is to edit a model in a modal dialog. The only difficulty here is that our model is only known at runtime. No problem though as we will use the dynamic nature of Jspresso.
public class CreateEntityFromLOVAction<E, F, G> extends EditComponentAction<E,F,G> {
#Override
protected Object getComponentToEdit(Map<String, Object> context) {
IEntityFactory entityFactory = getBackendController(context).getEntityFactory();
IQueryComponent lovQueryComponent = (IQueryComponent) context.get(IQueryComponent.QUERY_COMPONENT);
Class<IEntity> entityToCreateContract = lovQueryComponent.getQueryContract();
IEntity entityInstance = entityFactory.createEntityInstance(entityToCreateContract);
setActionParameter(Arrays.asList(entityInstance), context);
return entityInstance;
}
#Override
protected IViewDescriptor getViewDescriptor(Map<String, Object> context) {
IEntityFactory entityFactory = getBackendController(context).getEntityFactory();
IQueryComponent lovQueryComponent = (IQueryComponent) context.get(IQueryComponent.QUERY_COMPONENT);
Class<IEntity> entityToCreateContract = lovQueryComponent.getQueryContract();
IComponentDescriptor<?> entityToCreateDescriptor = entityFactory.getComponentDescriptor(entityToCreateContract);
BasicComponentViewDescriptor formViewDescriptor = new BasicComponentViewDescriptor();
formViewDescriptor.setModelDescriptor(entityToCreateDescriptor);
return formViewDescriptor;
}
}
If you look at the code above, our new action takes care of the following :
Get the type of entity to create from the context. For this, we are just exploring the query component which is the model of the LOV dialog.
Create the entity instance and set it as action parameter in the context for the chain to continue working on it (save, close dialog).
Create a form to display in the creation dialog.
Points 1 and 2 are handled by the getComponentToEdit method and point 3 by the getViewDescriptor method.
Next, when the user clicks Ok, we have to save the entity, add it to the LOV result list and close the creation dialog.
For this, we will create a new action and chain it to the saveAction and closeDialogAction built-in actions.
public class CreateEntityFromLOVPersistAction<E, F, G> extends FrontendAction<E,F,G> {
#Override
public boolean execute(IActionHandler actionHandler, Map<String, Object> context) {
if (super.execute(actionHandler, context)) {
IQueryComponent lovQueryComponent = (IQueryComponent) context.get(IQueryComponent.QUERY_COMPONENT);
List<IEntity> createdEntityInstance = getActionParameter(context);
lovQueryComponent.setQueriedComponents(createdEntityInstance);
return true;
}
return false;
}
}
And the final wiring in SJS frontend.groovy:
action('createEntityFromLovOkAction', parent: 'okDialogFrontAction',
class:'test.CreateEntityFromLOVPersistAction',
wrapped: 'saveBackAction', next: 'closeDialogAction')
action('createEntityFromLovAction', parent: 'editComponentAction',
class: 'test.CreateEntityFromLOVAction',
name:'add.name', custom: [
okAction_ref: 'createEntityFromLovOkAction'
]
)
action('lovAction', parent: 'lovActionBase',
class:'test.LovActionWithCreate',
custom: [createAction_ref:'createEntityFromLovAction']
)
A long answer for less than 100 lines of code, but now you have a fully generic LOV action where the user can create any missing master data without leaving his current screen.
Presetting some data in the LOV filter depending on the user context :
For this, we generally use the initialization mapping that allows for setting some restrictions (either static or dynamic) on a reference property when it is queried in a LOV. For instance, let's consider the following use case :
You have 2 entities, Contract and Tariff, that are linked together through a 1-N relationship, i.e. a Contract is linked to 1 Tariff.
Contract and Tariff both have a country property and a Tariff can be assigned to a Contract if and only if they belong to the same country.
Tarrif has a status property and can only be used in a Contract if its status is ACTIVE.
You can simply enforce these rules in the LOV by setting the initialization mapping on the reference property the following way :
Entity('Contract', ...) {
...
reference 'tariff', ref: 'Tariff',
initializationMapping: [
'country': 'country',
'status': 'ACTIVE'
]
...
}
Thinking about it, this kind of behavior might very well find its way to the framework, so please, feel free to ope an enhancement request in the Jspresso GitHub.
I just started to develop a JavaFX application. Maybe I didn't get how JavaFX uses the TableView and I should use something different instead.
Currently my TableView displays data in multiple columns an when I double-click a cell the background color changes (by setCellFactory(customFactory)).
Now I want to access different cells of the table by using indices (column,row) and checking the background color.
The cells with a changed background color should be stored after a certain button was clicked.
I would like to get every cell with changed background(get celltext) for each row and store this for later use in a data structure like a Map>.
Would be really nice if somebody can give me a hint. Thank for your Help.
I suppose, you are adding an EventHandler to the TableCell, which is returned by your customFactory. This EventHandler is handling the doubleclick-event and sets the background color, right?
This handler has access to the parameter which is passed to the Callbacks/CustomFactories call-method, which contains the model-bean of the current row. You could set a flag or the columns name in that model-bean when a doubleClickEvent occurs.
Then
after a certain button was clicked
you can get your info, by checking the tables items. The row-index of each item is equivalent to the index of this item in the List of TableView#getItems
Also have a look at http://controlsfx.bitbucket.org/org/controlsfx/control/spreadsheet/SpreadsheetView.html if you need more TableFunctions.
EDITED
This is a code-example:
The Model-Bean used in TableView:
class Model {
private String propertyA;
private String propertyB;
#lombok.Getter
private Set<String> propertiesClicked = new HashSet<>();
The javafx-controls, annotate them with #FXML if you use FXMLs:
private TableView<Model> tableView;
private TableColumn<Model, String> propertyAColumn;
private TableColumn<Model, String> propertyBColumn;
and the the CellFactory. Create a more generic CellFactory if you need it for multiple columns:
propertyAColumn.setCellFactory((value) -> {
TableCell<Model, String> tableCell = new TableCell<Model, String>() {
//Override the Methods which you need
};
tableCell.setOnMouseClicked((mouseEvent) -> {
if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
if (mouseEvent.getClickCount() == 2 && !tableCell.getStyleClass().contains("buttonClicked")) {
tableCell.getStyleClass().add("buttonClicked");
tableView.getSelectionModel().getSelectedItem().getPropertiesClicked().add("propertyA");
}
}
});
return tableCell;
});
I am new to asp .net MVC 4.
I have one text box and the text box value I am fetching from one table.But while clicking on submit button this value I want to insert into different table , which is not inserting and showing error.It is taking value as null.
coding
View
#Html.TextBox("empname", (string)ViewBag.empname, new { #readonly = "readonly" })
controller
[HttpGet]
public ActionResult Facilities()
{
mstEmpDetail emp = new mstEmpDetail();
emp = db.mstEmpDetails.Single(x => x.intEmpId == 10001);
ViewBag.empname = emp.txtEmpFirstName;
return View();
}
[HttpPost]
public ActionResult Facilities(TrnBusinessCardDetail bc)
{
var empname1 = ViewBag.empname;
bc.txtfirstName = empname1;
db.TrnBusinessCardDetails.Add(bc);
db.SaveChanges();
return RedirectToAction("Facilities");
}
While I was working with normal text box it was inserting properly,but when I have retrieve
fro DB then i am getting this problem ?
How to solve this problem ?
Viewbag is a one way street - you can use it to pass information to the view, but you cannot use it to get the information from the view. The statement ViewBag.empname in your POST method has a value of null in your code.
As suggested by #dotnetom, ViewBag is a one way street. MVC is stateless so a POST request is not a "Round Trip" from previous get request. Thus your ViewBag can not hold its state.
MVC can determine (and construct) your action parameters from Form Parameters. In your case you have added a textbox with name "empname". So you should get this value as parameter in your POST request.
[HttpPost]
public ActionResult Facilities(TrnBusinessCardDetail bc, string empname)
{
bc.txtfirstName = empname;
db.TrnBusinessCardDetails.Add(bc);
db.SaveChanges();
return RedirectToAction("Facilities");
}
This would be simplest of solution given your problem. More appropriate would be binding your textbox directly with you model property. This way you will not have to worry about retrieving and assigning property value to model in your controller.
I think the problem is when you are using var empname1 = ViewBag.empname; in post controller because ViewBag.empname lost its value at that time.
I am trying to figure out the best way to accomplish this given the modern versions. I have am using VS2012 MVC4 EF5 and have built a edmx file from my database. I built a form that will allow submission of vendor information. The main table is Vendor table that contains mainly contact information and there are additional tables that store their multiple category choices (checkbox list) and another that stores their minority info (collection of radio buttons). So my ViewModel is the vendor table and I populate the checkboxes and radio buttons with view bags that query the lookup tables for their values.
So I assume I should either build the categories and minority parts into the ViewModel and somehow wire up the magic so that the database knows how to save the returned values or should I just use viewbags and then somehow on post read those values and loop through them to store them to the database? Either way I am stuck and don't know how to do this.
I have serached numerous examples online but none of them fit this situation. The is not a complex data model but should be rather common real world situation. I am new to MVC so forgive me if I am missing something obvious.
Any guidance is appreciated.
UPDATE: Here is the baseic code to save the ViewModel to the db but how do you save the checkbox list and radio buttons. I think there are two approaches 1) to somehow include them in the ViewModel or 2) perform a separate function to save the form checkbox and radio button values.
[HttpPost]
public ActionResult Form(VendorProfile newProfile)
{
if (ModelState.IsValid)
{
newProfile.ProfileID = Guid.NewGuid();
newProfile.DateCreated = DateTime.Now;
_db.VendorProfiles.Add(newProfile);
_db.SaveChanges();
return RedirectToAction("ThankYou", "Home");
}
else
{
PopuplateViewBags();
return View(newProfile);
}
}
Perhaps another way of stating my problem is what if you had to build an form to where people would sign up and select all their favorite flavors of ice cream from a list of 31 flavors. You need to save the person's contact information in the primary table and then save a collection of their flavor choices in another table (one-to-many). I have a ViewModel for the contact form and a list of flavors (checkbox list) displayed from a lookup table. How do you write code to save this form?
SOLUTION: There might be a better way, but wanted to post what I discovered. You can pass in the collection of checkboxes and then send them to another method that handles the db inserts.
[HttpPost]
public ActionResult Form(VendorProfile newProfile, int[] categories)
{
if (ModelState.IsValid)
{
newProfile.ProfileID = Guid.NewGuid();
newProfile.DateCreated = DateTime.Now;
_db.VendorProfiles.Add(newProfile);
_db.SaveChanges();
InsertVendorCategories(newProfile.ProfileID, categories);
return RedirectToAction("ThankYou", "Home");
}
else
{
PopuplateViewBags();
return View(newProfile);
}
}
private void InsertVendorCategories(Guid ProfileID, int[] categories)
{
try
{
var PID = new SqlParameter("#ProfileID", ProfileID);
var CID = new SqlParameter("#CatID", "");
foreach (int c in categories)
{
CID = new SqlParameter("#CatID", c);
_db.Database.ExecuteSqlCommand("Exec InsertVendorCategory #ProfileID, #CatID", PID, CID);
}
}
catch { Exception ex; }
}