Getting fragment's id into detail controller - data-binding

I'm working on a sap fiori Master-Detail application on sap web ide.
i want to filter a table i have on detail view based on an ID i will get from a list in master view.The table's detail view is located in a fragment. I created a js function to filter that table in the detail controller but i can't seem to have the id of the table in the fragment.
Here's my detail-controller's code:
this._oView = this.getView();
this._oView.attachAfterRendering(function() {
var sPath1 = "Qmnum";
var sOperator1 = "EQ";
var sValue1 = "10000000";
var oFilter1 = new sap.ui.model.Filter(sPath1, sOperator1, sValue1);
var oBinding = this.byId("tableid").getBinding("items");
oBinding.filter(oFilter1);
});
i tried using also this
sap.ui.getCore().byId();
&
this.getView().byId();
but still undefined.

If XML fragments are used within XML views, giving the view ID as
fragment ID will allow calling this.byId(…) in the view’s controller
to retrieve controls inside the fragment.
var oFragment = sap.ui.xmlfragment(this.getView().getId(), "my.useful.VerySimpleUiPart" );

Initialize the fragment and attach it to the current view:
// Init fragment
var oFragment = sap.ui.xmlfragment("herePutJourneyToFragment.fragmentName", this.getView().getController());
// Attach the fragment to the current view
this.oView.addDependent(oFragment);
After that you should be able to find the table in you view:
var oTable = this.byId("tableid");
EDITED 13:45 150317 bellow:
Tutorial.

Related

Devexpress XAF (Blazor) Popup window to edit property

I have an XAF application. Most of my Business Objects are based on a baseclass "MyBaseClass" which contains Createdby, ModifiedBy, ... Comments. The Comments field is AllowEdit=false. I only want users to be able to modify the comment thru an action which would allow them to create an entry to which I would prepend their UserName and timestamp.
I don't know how to pop up a window to edit a property (string) within the current object and view.
There are plenty of examples of how to CreateListView but in this case what I wish to edit in the popup is not a separate BO but just a string. Maybe that is my problem(???)
I have the Action Controller and I am not sure how to create the DetailView when I get into the _Execute()
In Winforms XAF I add an action in a view controller.
In the action's execute event I call something like
private void actOpenDetailView_Execute(object sender, SimpleActionExecuteEventArgs e)
{
var application = Controller.Application
var viewId = application.FindDetailViewId(typeof(MyBusinessObject));
application.CreateObjectSpace(typeof(MyBusinessObject));
var detailView = application.CreateDetailView(newObjectSpace, jh, true);
e.ShowViewParameters.CreatedView = detailView;
e.ShowViewParameters.TargetWindow = TargetWindow.NewWindow;
}
I haven't tried that in Blazor.

Xamarin Form passing parameters between page keep a hard link to it

I try the new Shell of Xamarin Form 4 for a small project.
I have a list of order, then someone chooses an order and start picking some inventory for this order with barcode. To be simple, I use 2 views and 2 viewmodel.
The process is:
1. User select an order the click a button "pickup"
2. I use ViewModelLocator (TinyIoc) to resolve the correct ViewModel of the pickup view
3. I call Initialize on the new ViewModel and pass some parameters needed. Like a list of items needed to be pickup.
4. Open the view in modal state.
I don't understand that if I change some qty in the list I pass on the second viewmodel, then hit the back button (modal view close). The quantity changed is now in the original viewmodel. How this is possible? I was thinking that passing parameter to a function do not share the same variable but just copy it??
Viewmodel of the first view (look at the Initialize function the List passed and the JobEnCours object)
private async Task GoPickup()
{
Device.BeginInvokeOnMainThread(async () =>
{
if (this.CodeJob != null && this.CodeJob != "")
{
this.IsBusy = true;
PrepChariotSP3ViewModel vm = ViewModelLocator.Resolve<PrepChariotSP3ViewModel>();
await vm.InitializeAsync(this._jobEnCours, this.ComposantesPick.ToList()) ;
await Shell.Current.Navigation.PushAsync(new PrepChariotSP3Page(vm));
this.IsBusy = false;
}
});
}
the the Initialize code on the second Viewmodel (look I set the JobEnCours.Description=Test)
public async Task InitialiseAsync(Job jobEnCours, List<ComposantePick> composantePick)
{
Title = "Ceuillette: " + jobEnCours.CodeProd;
this._jobEnCours = jobEnCours;
this.ComposantesPick = new ItemsChangeObservableCollection<ComposantePick>();
foreach(ComposantePick c in composantePick)
{
this.ComposantesPick.Add(c);
}
jobEnCours.Description = "test";
So, If I do the back button, then in the first VM the JobEnCours.Description is now set to "test" how this is possible?!
Any idea?

Relational Query - 2 degrees away

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();
}

Want To Copy Certain Fields From Previous Entry To New Fragment

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);

Master-Detail view - SAPUI5 : Passing argument from Master to Detail controller

In Master controller, on selection of item in the list, I am calling the detail view and binding the model data.
Master Controller:
itemSelected: function(result)(
var app = sap.ui.getCore().byId("appId");
var list = sap.ui.getCore().byId("mainListId");
var selectedItem = list.getSelectedItem();
var selectedPath = selectedItem.oBindingContexts.MainList.sPath;
var Item = sap.ui.getCore().getModel("MainList").getProperty(selectedPath);
var endPoint = Item.Endpoint;
console.log(endPoint);
var oModel =new sap.ui.model.json.JSONModel(Item);
sap.ui.getCore().setModel(oModel,'DetailItem');
app.toDetail('idDetail','slide')
},
Detail View:
I am able to bind the model data here in oTable.
oTable.bindRows("DetailItem>/");
1.How store the model data in a variable? (tried: sap.ui.core().getModel(modelname).getData() and similar others. This gives undefined, as it gets read even before the ItemSelected function in the Master controller is called.)
How to bind/get the model data into Detail controller after the itemSelected function is called?
Thanks!
You can set the model to i.e. a view by using the following statement:
this.getView().setModel(oModel, "modelID");

Resources