My Vaadin application provides a little table, which is editable.
If the user - after changing some fields - clicks on the save button, I will receive all the rows and save the changed rows into the database.
// create a bean item container
val writers: BeanItemContainer[Person] = new BeanItemContainer[Person](classOf[Person])
// create some person objects
writers.addBean(new Person("Thomas", "Mann", 1929))
writers.addBean(new Person("W. B.", "Yeats", 1923))
writers.addBean(new Person("Günter", "Grass", 1999))
// create the table incl. the bean item container
val table: Table = new Table("Nobel Prize for Literature", writers)
// set some options for the table
table.setImmediate(true)
table.setEditable(true)
table.setValidationVisible(true)
// create the save button
val saveButton = new Button("save")
// create a table listener
saveButton.addListener(new Button.ClickListener() {
def buttonClick(event: com.vaadin.ui.Button#ClickEvent) {
table.commit()
val writerList = table.getItemIds.asInstanceOf[Collection[Person]].asScala.toList
//
// **THIS WILL NOT WORK**
//
// I received always the original rows, without the
// user input, but I needs the user input, the changed rows.
//
//
for (item <- writerList) {
println("firstName ====> " + item.getFirstName)
println("lastName =====> " + item.getLastName)
println("year==========> " + item.getYear)
}
}
});
How can I receive the changed rows with the user input? Is it necessary to implement a form? If yes, how I can implement a form in this case?
Vaadin does not keep track of modified items in a container. You have to track the modifications in your beans (Person). Define setters for all editable properties and set a modified flag if something changes. In the save button listener you can filter out all modified items.
Related
It's possible to reset a table scala swing or remove it from the container after clicking on a button ?
I've tried to create a val with that table but I have always a new table stacked under the old
Here is the code :
// here is the most crucial part when the user click on the button, it will append a new table but if we want to start again, it will append bottom of the old one and I want here a kind of reset or removing of table
contents = new BoxPanel(Orientation.Vertical) {
contents += new Label("Hello, you're welcome")
contents += Button("Query") {
val query: ScrollPane = new ScrollPane(changeCountry())
contents -= query
Try {
contents += query
}.getOrElse(Dialog.showMessage(contents.head, "Incorrect input ! This seems that input isn't in that list, write a different code or country"))
}
// this part will ask to the user to write text to the input to display the table in function of the parameter of my function
def changeCountry(): Table = {
val text = Dialog.showInput(parent = contents.head, message = "Write a code of a country or a country", initial = "test")
text match {
case Some(s) => airportRunwayByCountry(s)
}
}
// this below part creates the table
def airportRunwayByCountry(code : String): Table = {
val headers = Seq("Airport","Runway linked")
val rowData = Functions.findAirportAndRunwayByCountry(code).map(x => x.productIterator.toArray).toArray
val tableAirportRunway = new Table(rowData,headers)
tableAirportRunway}
}
Solved with method "remove" of containers
Here is the code :
Try {
if(contents.length == 3 \\ number of items in my Box) {
\\ at this moment, only add the table because none other table exists
contents += new ScrollPane(changeCountry())
}
else {
contents -= contents.remove(3) \\get the id of the old table and remove it at this position
contents += new ScrollPane(changeCountry()) \\ at this moment, this content will have the id n°2, and the loop can start over without errors
}
I have a Entity Framework based database with a few entities/models/table. For e.g. Documents Model, I am want to track all changes to each record in that table, in a seperate table called DocumentChanges Model/Table.
Could you please guide me on how to enable/tell EF to track/audit all changes to the table in a separate table?, not just a date time stamp, but save the full record for every change in a separate table.
The library Audit.EntityFramework can help you to do what you want.
You'll need to implement your own DataProvider to store the data formatted as you wish.
For example:
void StartUp()
{
//Setup to use your own provider to store the data
Audit.Core.Configuration.Setup()
.UseCustomProvider(new YourDataProvider());
//Setup to audit EF operations only for the table Documents
//(Your DbContext must inherit from AuditDbContext)
Audit.EntityFramework.Configuration.Setup()
.ForAnyContext(x => x.IncludeEntityObjects())
.UseOptIn()
.Include<Documents>();
}
class YourDataProvider : AuditDataProvider
{
public override object InsertEvent(AuditEvent auditEvent)
{
//Get some enviroment info:
var userName = auditEvent.Environment.UserName
//Get the complete log for the EF operation:
var efEvent = auditEvent.GetEntityFrameworkEvent();
foreach(var entry in efEvent.Entries)
{
// each entry is a modified entity (updated, deleted or inserted)
if (entry.Action == "Update")
{
//You can access the column values
var value = entry.ColumnValues["ID"];
//...or the columns changes
var changes = entry.Changes.Select(ch => ch.ColumnName + ": " +
ch.OriginalValue + " -> " + ch.NewValue);
}
//... insert into DocumentChanges table
}
return id;
}
}
I want to pass more than one record between two forms. The user opens Form-A, selects multiple records and then clicks a button that opens Form-B.
In Form-B there are two (or more) StringEdit controls and they should display values from the selected records.
I know how to pass only one record, to do that I use the following code in a method of Form-B:
if (element.args().parmEnumType() == enumNum(NoYes)
&& element.args().parmEnum() == NoYes::Yes)
{
myTable = element.args().record();
stringEdit.text(myTable.Field);
}
How should I change my code so that I can set the text of another StringEdit control to the field value of the next record that the user selected?
To do this, you can use an args to pass the records, which you will need to prepare in your Form-A, as below (taking the SalesTable as example);
int recordsCount;
SalesTable salesTable;
container con;
Args args = newArgs();
// gets the total records selected
recordsCount = salesTable_ds.recordsMarked().lastIndex();
salesTable = salesTable_ds.getFirst(1);
while(salesTable)
{
// storing recid of selected record in container
con = conIns(con,1, salesTable.RecId);
salesTable = SampleTable_ds.getNext(); // moves to next record
}
// passing container converted to string
args.parm(con2Str(con,','));
Then on your Form-B, you will need to override the init() method to read the args you created,
In order to retrieve passed arguments in the recipient from. Override the init() method of new form as shown
public void init()
{
container con;
int i;
super();
// string to container
con = str2con(element.args().parm(),'','');
// for sorting
for(i = 1;i<= conLen(con) ;i++)
{
salesTable_ds.query().dataSourceTable(Tablenum(SalesTable)).addRange(fieldNum(SalesTable,RecId)).value(SysQuery::value(conPeek(con,i)));
}
}
Hope it helps.
Taken from Ax-Forum
This will typically imply looping through the selected records in Form-A and changing the query in Form-B.
The idiomatic way to loop through selected records involves a for loop and the getFirst and getNext methods of the datasource:
SalesLine sl;
FormDataSourcs ds = _salesLine.dataSource();
for (sl = ds.getFirst(true) ? ds.getFirst(true) : ds.cursor(); sl; sl = ds.getNext())
{
//Do your thing, add a query range
}
The MultiSelectionHelper class may be of use here, as it does the thing:
public void init()
{
MultiSelectionHelper ms;
super();
if (element.args() && element.args().caller() && element.args().record())
{
this.query().dataSourceTable(tableNum(SalesLine)).clearDynalinks();
ms = MultiSelectionHelper::createFromCaller(element.args().caller());
ms.createQueryRanges(this.query().dataSourceTable(tablenum(SalesLine)), fieldstr(SalesLine, InventTransId));
}
}
Grid g=new Grid(arg0.size(),5);
g.setBorderWidth(5);
g.setTitle("users data");
g.setVisible(true);
g.setCellSpacing(3);
g.setCellPadding(2);
g.setText(0,0, "empid");
g.setText(0,1, "first name");
g.setText(0,2, "last name");
g.setText(0,3, "gender");
g.setText(0,4, "studies");
System.err.println("list = "+arg0);
for(int i=0;i<arg0.size();i++)
{
User data= (User) arg0.get(i);
for(int row=1;row<arg0.size();row++)
{
for(int col=0;col<5;col++)
{
g.setText(row, col,String.valueOf(data.getEmpid()));
g.setText(row, col,data.getFirstname());
g.setText(row, col, data.getLastname());
g.setText(row, col,data.getGender());
g.setText(row, col, data.getStudies());
}
}
}
RootPanel.get().clear();
RootPanel.get().add(g);
arg0 is list of User pojo. in every column the last field is only adding but we have to add appropriate data into each column. mostly i did wrong in for loop please correct me and give response
To add the data correctly, have the for-loop like this:
// make the grid the size of the userlist + 1 for the header line
Grid g = new Grid(arg0.size() + 1, 5);
// rest of the Grid-definition
;
// per user in the user-list, add one row
for(int i=0;i<arg0.size();i++){
// retrieve the current user
User data= (User) arg0.get(i);
// add the data of that user in the correct column
// concerning the row: add in currentRow+1 to compensate for header row
g.setText(i+1, 0,String.valueOf(data.getEmpid()));
g.setText(i+1, 1,data.getFirstname());
g.setText(i+1, 2, data.getLastname());
g.setText(i+1, 3,data.getGender());
g.setText(i+1, 4, data.getStudies());
}
However, another way would be using a CellTable. It is much more flexible than your Grid, you can easily add/remove rows, and it's much easier to e.g. change the order of the columns, should that be necessary some time in the future. Additionally, it provides interfaces for column sorting should that be necessary. If you're interested in seeing a CellTable example, let me know so that I can update this post.
I'm trying to create a simple to-do-list app with an SQLite DB and a Drag-Sort ListView.
Right now I am binding data from an SQLite database cursor into a ListView using a SimpleCursorAdapter and adding items with an EditText view as explained in this tutorial.
I have moved everything into one activity and I have swapped the plain ListView with a Drag-Sort ListView. My issue is connecting the DB and Drag-Sort ListView together. The DLSV demos use a predefined array to fill fill the DSLV.
Snippet form DSLV:
DragSortListView lv = (DragSortListView) getListView();
lv.setDropListener(onDrop);
lv.setRemoveListener(onRemove);
array = getResources().getStringArray(R.array.jazz_artist_names);
list = new ArrayList<String>(Arrays.asList(array));
adapter = new ArrayAdapter<String>(this, R.layout.list_item1, R.id.text1, list);
setListAdapter(adapter);
Snippet from my existing code:
mDbHelper = new NotesDbAdapter(this);
mDbHelper.open();
...
mDbHelper.createNote(noteName, "");
fillData();
private void fillData() {
// Get all of the notes from the database and create the item list
Cursor c = mDbHelper.fetchAllNotes();
startManagingCursor(c);
String[] from = new String[] { NotesDbAdapter.KEY_TITLE };
int[] to = new int[] { R.id.text1 };
// Now create an array adapter and set it to display using our row
SimpleCursorAdapter notes =
new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);
}
Thank you and sorry if this doesn't make all that much sense.
Since you cannot reorder the items in a Cursor, you have to create a mapping between Cursor positions and ListView positions. This is done for you by the DragSortCursorAdapter class and subclasses so that the drag and drop reordering is maintained visually. If you need the new orders persisted (like to your database), then you must implement that logic yourself. The method getCursorPositions() will help you with this.
I have made use of Drag sort list view. Its amazing! but instead of using the dragsortcursoradapter i created my own trick. here it is.
What i have done is that whenever i swapped any item, i passed the new swapped list in an array to the database, deleted the table and recreated the new updated table. here is my code
here is the code snippet from my database handler
public void onUpdateToDoTable(ArrayList<Task> taskList) {
SQLiteDatabase db = this.getWritableDatabase();
db.execSQL("DROP TABLE IF EXISTS " + TABLE_TASKTODO);
String CREATE_TASK_TODO_TABLE = "CREATE TABLE IF NOT EXISTS "
+ TABLE_TASKTODO + "(" + SEQ_ID + " INTEGER PRIMARY KEY,"
+ TASK_NAME + " TEXT )";
db.execSQL(CREATE_TASK_TODO_TABLE);
for (int i = 0; i < taskList.size(); i++) {
ContentValues values = new ContentValues();
values.put(TASK_NAME, taskList.get(i).getTask());
db.insert(TABLE_TASKTODO, null, values);
}
db.close();
}
then on using drop listener
i called the above method..
private DragSortListView.DropListener onDrop = new DragSortListView.DropListener() {
#Override
public void drop(int from, int to) {
Task item = adapter.getItem(from);
adapter.notifyDataSetChanged();
adapter.remove(item);
adapter.insert(item, to);
db.onUpdateToDoTable(list);
Log.d("LIST", db.getAllToDoTasks().toString());
}
};
db is my object of database handler. whole source code is available at dragdroplistview. amazing example. this was a life saver for me. Ciao!
There is a github project available at https://github.com/jmmcreynolds/dslv-db-demo
This demo includes a working example of how to setup a DragSortListView that will save the changes that you make to the list (position, add/delete) to a database.
I have used it just now. Its perfect demo project available for using DSLV with SQLiteDB.
Thanks to github user jmmcreynolds.