I wonder how it would be possible to launch a series of popups, containing a form,
from code-behind.
I possess a list of objects 'Products'
and I wish I could change one property (quantity) of each "product".
Here's how I build my list (normally I use a database).
Private List<Product> listProduct;
listProduits = new List<Product>();
Product objProduit_1 = new Produit;
objProduct_1.ref = "001";
objProduct_1.article = "G900";
objProduct_1.quantity = 30;
listProducts.Add(objProduct_1);
ProductobjProduit_2 = new Product;
objProduct_2.ref = "002";
objProduct_2.article = "G900";
objProduct_2.quantity = 35;
listProduits.Add(objProduct_2);
And I would like displayed popup one after one.
Thank you in advance for your help
you'll need to write some client side code that produces what you're looking for. The AJAX Control tool kit may be along the lines of what you're looking for.
Related
I'm after something like the application output window in Visual Studio, like so:
I'd like to be able to:
bind to an ObservableCollection of strings
select and copy text (as shown in the screenshot above)
At present this is for a Mac app, although iOS may follow later.
I've tried these:
Editor - Problem is it only exposes a Text property that I can bind to and not a collection. Sooner or later, the maximum string length will be reached.
ListView with Label for ViewCell - Problem is text from a Label is not selectable, let alone having multiple lines (bound collection items) selectable.
Using a custom renderer for Mac that makes use of NSTextView and appending to textStorage every time a new item is added, but again, there’s a limit to how much you can add to textStorage.
I'm open to using third-party tools such as Syncfusion, if that makes it easier.
Custom a method to deal with list data to combine them into a newline string :
public string formatstring(NSArray objects)
{
StringBuilder stringBuilder = new StringBuilder();
for(nuint i=0;i< objects.Count; i++)
{
stringBuilder.Append(objects.GetItem<NSString>(i) +"\n");
}
return stringBuilder.ToString();
}
Then used in NSTextView as follow :
string[] items = new string[] {"111111" , "222222" , "333333" , "444444" , "555555" };
NSArray array = NSArray.FromStrings(items);
NSTextView textView = new NSTextView(new CGRect(100,160,200,100));
textView.BackgroundColor = NSColor.Gray;
textView.Value = formatstring(array);
View.AddSubview(textView);
The effect :
I am building an application that will have the ability to create agenda items to discuss in a meeting. The agenda item might include one or more attachments to discuss so there is a one to many relation between the AgendaItems and the AgendaDocs models. So far, I have an insert form that looks like this:
The "Select File" button is a drive picker and the code I have inside the onDocumentSelect event is the following:
var docs = result.docs;
var createDataSource = app.datasources.AgendaDocs.modes.create;
for(var i=0; i<docs.length-1; i++){
var uniqueDraft = createDataSource.item;
createDataSource.items.push(uniqueDraft);
}
for(var i=0; i<createDataSource.items.length-1; i++){
var draft = createDataSource.item;
createDataSource.items[i].DocTitle = docs[i].name;
createDataSource.items[i].DocURL = docs[i].url;
createDataSource.items[i].DriveID = docs[i].id;
}
console.log(createDataSource.items);
The code is supposed to fill out the the List widget below the "Select File" button, but as how you see, the three items are the same. The datasource of the List widget is "AgendaDocs.modes.create" and the datasource of the insert form is "AgendaItems.modes.create".
Reading the official documentation from appmaker, makes me think it is possible since the properties of "CreateDataSource" includes "items". I need help from an expert here. Is this possible? Am I using the wrong approach?
First things first, it seems that you are trying to create records from different models and relationship between them in a one call... at this time App Maker is not that smart to digest such a complex meal. Most likely you'll need to break your flow into multiple steps:
Create (persist) Agenda Item
Create AgendaDocs records and relation with AgendaItem
Similar flow is implemented in Travel Approval template app, but it is not exactly the same as yours, since it doesn't create associations in batches.
Going back to the original question. Yep, it is possible to have multiple drafts, but not with the Create Datasource. You are looking for Manual Save Mode. Somewhere in perfect world your code would look similar to this:
// AgendaItems in Manual Save mode
var agendaDs = app.datasources.AgendaItems;
// this line will create item on client and automatically push it
// to ds.items and set ds.item to it.
agendaDs.createItem();
var agendaDraft = agendaDs.item;
// Field values can be populated from UI via bindings...
agendaDraft.Type = 'X';
agendaDraft.Description = 'Y';
// onDocumentSelect Drive Picker's event handler
var docsDs = agendaDs.relations.AgendaDocs;
result.docs.forEach(function(doc) {
// this line will create item on client and automatically push it
// to ds.items and set ds.item to it...however it will throw an exception
// with this message:
// Cannot save a foreign key association for the 'AgendaItem'
// relation because the target record has not been persisted
// to the server. To fix this, call saveChanges()
// on the data source for that record's model: AgendaItem
docsDs.createItem();
var docDraft = docsDs.item;
docDraft.DocTitle = doc.name;
docDraft.DocURL = doc.url;
docDraft.DriveID = doc.id;
});
// submit button click
agendaDraft.saveChanges();
I have three models:
Timesheets
Employee
Manager
I am looking for all timesheets that need to be approved by a manager (many timesheets per employee, one manager per employee).
I have tried creating datasources and prefetching both Employee and Employee.Manager, but I so far no success as of yet.
Is there a trick to this? Do I need to load the query and then do another load? Or create an intermediary datasource that holds both the Timesheet and Employee data or something else?
You can do it by applying a query filter to the datasource onDataLoad event or another event. For example, you could bind the value of a dropdown with Managers to:
#datasource.query.filters.Employee.Manager._equals
- assuming that the datasource of the widget is set to Timesheets.
If you are linking to the page from another page, you could also call a script instead of using a preset action. On the link click, invoke the script below, passing it the desired manager object from the linking page.
function loadPageTimesheets(manager){
app.showPage(app.pages.Timesheets);
app.pages.Timesheets.datasource.query.filters.Employee.Manager._equals = manager;
app.pages.Timesheets.datasource.load();
}
I would recommend to redesign your app a little bit to use full power of App Maker. You can go with Directory Model (Manager -> Employees) plus one table with data (Timesheets). In this case your timesheets query can look similar to this:
// Server side script
function getTimesheets(query) {
var managerEmail = query.parameters.ManagerEmail;
var dirQuery = app.models.Directory.newQuery();
dirQuery.filters.PrimaryEmail._equals = managerEmail;
dirQuery.prefetch.DirectReports._add();
var people = dirQuery.run();
if (people.length === 0) {
return [];
}
var manager = people[0];
// Subordinates lookup can look fancier if you need recursively
// include everybody down the hierarchy chart. In this case
// it also will make sense to update prefetch above to include
// reports of reports of reports...
var subortinatesEmails = manager.DirectReports.map(function(employee) {
return employee.PrimaryEmail;
});
var tsQuery = app.models.Timesheet.newQuery();
tsQuery.filters.EmployeeEmail._in = subortinatesEmails;
return tsQuery.run();
}
Short Version: I want to have my Copy button in a table to be able to grab the values from an existing entry and populate those into a "Create Entry" Page Fragment. This way users don't have to reenter all the data when making a new entry.
Long Version:
I have two buttons added the rows in my table: Edit and Copy.
The Edit Button uses the following code to grab the information from that specific row and uses the Fragment to edit the entry.
widget.datasource.saveChanges();
app.datasources.SystemOrders.selectKey(widget.datasource.item._key);
app.showDialog(app.pageFragments.SystemOrders_Edit);
The Copy button is currently using the following code to duplicate the entry and automatically create it.
//Allows for copying table/row
var rowDataSource = widget.datasource;
var listDatasource = app.datasources.SystemOrders_HideComplete;
var createDataSource = listDatasource.modes.create;
widget.datasource.saveChanges();
// Enter fields you want to duplicate below
createDataSource.item.ProjectName = rowDataSource.item.ShowName;
createDataSource.item.DeliveryInfo = rowDataSource.item.DeliveryInfo;
createDataSource.item.SOB = rowDataSource.item.SOB;
createDataSource.item.DeliveryDate = rowDataSource.item.DeliveryDate;
createDataSource.item.Company = rowDataSource.item.Company;
createDataSource.item.Location = rowDataSource.item.Location;
createDataSource.item.AdditionalPeripherals = rowDataSource.item.AdditionalPeripherals;
createDataSource.item.Notes = rowDataSource.item.Notes;
createDataSource.createItem();
I would like to change this behavior so that the Copy button grab the values from those specific fields, however instead of doing a createDataSource/createItem(); I want it to place those values into a Page Fragment (ex: SystemOrders_Add) that has the corresponding fields.
This way the user can click "Copy" and the SystemOrders_Add Fragment appears with pre-populated values.
I want to make sure these values are only in the Page Fragment and do not get commited until the user presses the Submit button.
newSOEmailMessage(widget);
widget.datasource.createItem();
app.closeDialog();
Thank you for your help!
one way you can accomplish this is by passing the data to Custom Properties defined in your Page Fragment and then you can place those properties to the corresponding fields. I recommend you also check this article https://developers.google.com/appmaker/ui/viewfragments#use_custom_properties_to_customize_page_fragments
First you need to create the Custom Properties inside your Page Fragment. Then in your Copy button onClick event you can use something like this to save the row data from your table to the Custom Properties:
var rowDataSource = widget.datasource.item._key;
app.datasources.SystemOrders.selectKey(rowDataSource);
var projectName = app.datasources.SystemOrders.item.project_name;
var deliveryInfo = app.datasources.SystemOrders.item.delivery_info;
//...
app.pageFragments.SystemOrders_Edit.properties.ProjectName = projectName;
app.pageFragments.SystemOrders_Edit.properties.DeliveryInfo = deliveryInfo;
//...
app.showDialog(app.pageFragments.SystemOrders_Edit);
Assuming you have a form inside your Page Fragment, you can bind the value of each field with custom properties. Binding will ensure that the data is pre-populated. This can be done for each field via the Property Editor and the binding should look like this: #properties.ProjectName
Inside your Submit button onClick event you can use something like this to create a new item in the datasource using the values available in each field.
var projectName = widget.root.descendants.Field1.value;
var deliveryInfo = widget.root.descendants.Field2.value;
//...
var myDatasource = app.datasources.SystemOrders_HideComplete;
var myCreateDatasource = myDatasource.modes.create;
var draft = myDatasource.modes.create.item;
draft.project_name = projectName;
draft.delivery_info = deliveryInfo;
//...
// Create the new item
myCreateDatasource.createItem();
app.closeDialog();
You can set properties back to null once item is created (maybe onDetach) like this:
app.pageFragments.SystemOrders_Edit.properties.ProjectName = null;
Hope this helps!
I have a feeling that removing this line from the Copy Button click handler will make a trick(of course, if your page fragment is bound to ds.modes.create.item):
createDataSource.createItem();
In case, you are using Manual save mode and you are trying to reuse Page Fragment without overriding datasource... you need create new items using different approach:
// Copy Button click handler
var source = widget.datasource.item;
var listDatasource = app.datasources.SystemOrders_HideComplete;
// This line will add new item to the list datasource
// without saving it to database.
listDatasource.createItem();
var target = listDatasource.item;
// Enter fields you want to duplicate below
target.Field1 = source.Field1;
target.Field2 = source.Field1;
...
// Show fragment (assuming it is bound to listDatasource.item)
app.showDialog(app.pageFragments.EditItemFragment);
// -----------
// Page Fragment's Submit Button click handler
...
listDatasource.saveChanges(function() {
// TODO: handle successful save
});
Thank you to Pavel and Wilmar. The solution that worked for me is listed below:
//Allows for copying table/row
var rowDataSource = widget.datasource;
var listDatasource = app.datasources.SystemOrders_HideComplete;
var createDataSource = listDatasource.modes.create;
widget.datasource.saveChanges();
// Enter fields you want to duplicate below
createDataSource.item.ShowName = rowDataSource.item.ShowName;
createDataSource.item.DeliveryInfo = rowDataSource.item.DeliveryInfo;
createDataSource.item.SOB = rowDataSource.item.SOB;
createDataSource.item.Notes = rowDataSource.item.Notes;
app.datasources.SystemOrders.selectKey(widget.datasource.item._key);
app.showDialog(app.pageFragments.SystemOrders_Add);
(Deleted my old question to simplify it. )
I enter data in a table, I then want to make an exact duplicate of that data in a new item/record/row*.
*not sure the proper term.
Is there any way to accomplish this?
Sorry for the slow response. Here is what you should do:
Add a "copy" button in the row. In the onClick on that button, add this code:
var createDataSource = widget.datasource.modes.create;
var rowDataSource = widget.datasource;
createDataSource.item.foo = rowDataSource.item.foo;
createDataSource.item.bar = rowDataSource.item.bar;
// And so on for each field
createDataSource.createItem();
You could probably make sure of javascript for-in to loop through all the properties of the item in so you don't have to manually specify each record, but I didn't have time to experiment with this.
Edit:
The above code won't show the copied record in the list immediately, because I used row's create data source, instead of the lists create data source. Try this instead:
var rowDataSource = widget.datasource;
// Instead of using the row datasource for create, explicitly use the data source of your list.
var listDatasource = app.datasources.NameOfYourListsDataSource;
var createDataSource = listDatasource.modes.create;
createDataSource.item.foo = rowDataSource.item.foo;
createDataSource.item.bar = rowDataSource.item.bar;
// And so on for each field
createDataSource.createItem();