Send Data from Fragment to Main Activity through NavGraph - android-fragments

In my app, I'm using a Single Activity with multiple Fragments Architecture and I navigate between them using the Navigation Library. Within one of the fragments, I have multiple categories, each associated with an ID. When a category is clicked, I take the user to that respective category explainer screen with the code below.
val directions = MainNavGraphDirections.launchFragmentWithThisCategoryId(categoryId!!)
onRoute(AppRoute.Directions(directions))
The above code sends them to the explainer screen associated with the associated categoryId. All is well until this point, the right explainer screen gets launched based on the categoryId. Within this explainer screen, I have a deep-link with a tag chatbot://fragment/wizardintro that is supposed to let the main activity know the specific follow-up fragment to send the user to. I denote all the fragments that can receive this deep-link with the code below.
companion object{
const val DEEP_LINK = "chatbot://fragment/wizardintro"
}
In the MainActivity, I have a method that receives all the different deep linking intents and matches them to the tags that will launch the respective category fragment with the code below.
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
intent?.data?.toString().also { deepLink ->
when (deepLink) {
IntroductionFragment.DEEP_LINK ->{
val categoryId = intent?.getLongExtra("categoryId", 0L)
val directions = MainNavGraphDirections.actionGlobalGoalWizard(categoryId)
navController.popBackStack()
navController.navigate(directions)
}
}
Now my problem arises when I try to retrieve this categoryId in the Main Activity and pass it to the next fragment. I don't get anything and only the default Long gets passed along. I think the function override fun onNewIntent(intent: Intent?) { } in the MainActivity recieve any intent. To be clear, these intents are sent from the explainer fragment which is technically a fragment that loads a json. Within the json there is a "route": {"type": "route", "url": "chatbot:///fragment/wizardintro"
In the MainActivity, the onNewIntent functions receive these intents unpacks them with this line intent?.data?.toString().also ...then in the when statement picks a fragment that has a matching chatbot:///fragment/wizardintro
I said all this to say that the main activity doesn't actually gets the categoryId, it simply picks launching the neccessary fragment without actually having anything associated with the categoryId
This makes me think that the first clicked categoryId doesn't actually get passed to the MainActivity. Although, to me, this seems like it shouldn't be this hard to pass objects/data from a fragment to an activity. What am I missing? What can I read to educate myself more on this?
Thanks for your time and responses!

Since we already got to the conclusion that MainActivity is not getting categoryId, you just need to pass that categoryId with the deep-link.
However, there is no need for any communication from Fragment to Activity.
You could achieve the same result through communication only between Fragment to Fragment, and Activity to Fragment.
What you want to do is to look more closely on deep-links and android navigation in the AndroidDocs, click here.
As you can tell, there are different ways to go around this, starting with arguments for each fragment. Assigning categoryId as an argument to the Fragment would help you use the navigationController and navigate to the new Fragment, while passing the categoryId to it.
Now, I am aware that you also wish to launch it with a deep-link; there's also a good explanation on here. According to the docs, you can place arguments in deep-links in the following manner...
Placeholders in the form of {placeholder_name} match one or more characters. For example, http://www.example.com/users/{id} matches http://www.example.com/users/4. The Navigation component attempts to parse the placeholder values into appropriate types by matching placeholder names to the defined arguments that are defined for the deep link destination. If no argument with the same name is defined, a default String type is used for the argument value.
The navigation is something amazing and capable, you just need to be aware of everything it can actually do. You can even bind it to a BottomNavBar, with extremely minimal amount of code.
Try going over the AndroidDocs about it, and it'll grow on you for sure.

Related

fragment vs activity onClickButton functions - where is right place

I made an andorid application using the "activity" component. I used it for a while, but over time I found that one page was not enough for me. I needed to add tabLayout, viewPager2 and three fragments.
I needed to migrate the functionality from mainActivity to the firstFragment.
I encountered a problem with events during the XML migration. In the activity I called android: onClick = "myOnClicFunction". But is that not possible?
I know that this has been discussed several times here in several threads. However, I would like to ask how to proceed correctly.
Here in the thread Android Fragment onClick button Method is the advice "even if you are in the fragment, put the onClick functions into activity" there is another similar advice to, "if you insist to make it in a fragment"
But what is right? Should the onclick function be correct in the activity or in the fragment?
I don't want to put the source code here, because I don't know which procedure is correct at all.
I am creating a program that is for testing students. An example is displayed and a response is pending.
The first tab has a lot of buttons + saves the result to an xml files.
The second tab will contain statistics. From saved files displays how many calculations were correct, wrong, average response time, etc ...
In Activity I had functions like getQuestion(), evaluateQuestion(), saveToXml() and events zeroWasPressed(), oneWasPressed(), twoWasPressed(), threeWasPressed() ...
Where should I put all these functions when I change the application from Activity to Fragment?
on click function listener should be placed in corresponding fragment, where the button is added in fragment layout.
events zeroWasPressed(), oneWasPressed(), twoWasPressed(), threeWasPressed() ... should be placed inside corresponding fragment where those buttons were added in layout.
getQuestion(), evaluateQuestion(), saveToXml() , this function can be placed in your activity or some other custom classes, that would appropriate according to architecture viewpoint.

How to get return value in this case? (Java FX)

I'm writing part of a cross-platform application, where we mostly use REST (jersey) and Hibernate to communicate between systems. I'm new to JavaFX, but my side of the program should use it to get input values from users. Here is how the code flow would look:
public class startingClass{
...
public void startingMethod(Payload payload){
//send REST requests to different places with different payloads, like:
Response response = Utility.sendPostRequest(URI, payload2);
something = response.readEntity(something.class)
//more processing with the returned values
...
}}
In one of the places where I sent a request:
#Path("something")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
public class Resource{
...
#POST
#Path(something)
public Response doSomething(Payload payload) {
//show JavaFX window with text fields and an okay button
JavaFXClass.launch(JavaFXClass.class);
/* THIS IS WHERE I would need to get back the input values somehow */
//payload3 has the input values I need to send back
return Response.entity(payload3).build();
}}
The JavaFX class extends application and and overrides the (void) start method where I put together the window I want to show and after the button click (if inputs are okay) I close the window.
So the idea is that the startingMethod would have to wait, until the response comes back (maybe return with some default values, if the user doesnt type in anything for a minute - what would be the elegant solution for that?) with the input values. This would guarantee the sync.
If I use more REST or database saves inside the JavaFX class then I can't be sure the values are there by the time I wanna use them in the startingMethod (probably not) and it's probably a really bad looking solution anyway.
What could I do? I dont know much about callback methods in javafx, can those help me here? Thanks!
In the end I moved the JavaFXClass into the Resource class. Meaning Resource class extends Application, overrides start, etc. In the doSomethingMethod I call launch in a try-catch block, catch the IllegalStateException if needed and call start() instead (also in a try-catch block). The textfield input values are stored in a global variable after.
Also in the start() method I havePlatform.setImplicitExit(false);
so the doSomethingMethod() can be called multiple times without a problem, starting the javaFX window. It's not a pretty solution.

Call child form programmatically with parameter / filter

I'm creating a customization where on a click of a button, I need to allocate a charge for a particular purchase order / invoice journal.
From the front end, I would accomplish this by following the purchase order life-cycle and invoicing it. I would then go under the invoice tab of the PO, click Invoice Journals -> Charges -> Adjustment . This will open up my desired form where I will select a charges code, charges value, currency and category, and then I will click 'Ok' and have the system take care of the rest of the process.
Form name: MarkupAllocation_VendInvoiceTrans
Parent form Name: VendInvoiceJournal
You can see that the child form gets called with a few parameters such as the invoice number, there obviously needs to be that link. If I go into the AOT under forms, I right click and open up VendInvoiceJournal, but I wouldn't be able to open up MarkupAllocation_VendInvoiceTrans because it requires parameters.
Objective:
A: To open MarkupAllocation_VendInvoiceTrans through code where I manually pass those parameters to link to the parent table. I would provide the invoice number and such. The objective is to skip opening the parent table and manually going into the adjustments. I want to open that form directly and have it link to whichever record I specify.
B: I need to be able to pass a _ChargesValue parameter and have that be pre-populated for me. I don't know if this is possible, so I wanted to ask and confer. Ideally, I should be able to click a button on my custom form, and have MarkupAllocation_VendInvoiceTrans form directly open for a specified invoice, with pre-populated values on the line.
I know I should be tackling this problem one step at a time, so step A is priority number one.
I can open up the parent form with relative ease like so, but I cannot do the same for the child form. Obviously the same time of approach won't work, as I need to specify the relationship of the parent table before I open it.
private void allocateMarkup()
{
Object formRun;
Args args = new Args();
VendInvoiceJour jourTable;
;
select * from jourTable where jourTable.PurchId == 'PO000001191';
args.name(formstr(VendInvoiceJournal));
args.record(jourTable);
formRun = ClassFactory.formRunClass(args);
formRun.init();
formRun.run();
formRun.wait();
}
How would I be able to do so?
(Side note, I realize this whole form calling could be avoided if do all the transactions programmatically instead of letting the out of the box functionality handle it, but the markup and allocation logic is a beast of it's own and to me seems much more complicated than doing this. If someone has done it this manual way, any help on that would be greatly appreciated as well)
If I read your post right, you just want to open the Charges>Adjustment for a certain invoice. Here is one simple method:
MarkupAdjustment markupAdjustment = new MarkupAdjustment();
markupAdjustment.vendInvoiceJour(VendInvoiceJour::findFromPurchId('PO 120079'));
markupAdjustment.run();

Update Gridx with JsonStore, on event?

I am new to Web UI, Dojo, Java etc. If you are referring any advance topic please give some reading reference. It will help.
Context:
I have Gridx design using JsonStore, which takes a target + id for URL. With fixed "id" Grid loads well.
I have Dynamic Tree. It is working fine with lazy-loading etc.
Objective:
Based on click (or dblclick) event for a given node in Tree, I have to load Gridx with data. Hence, if tree node "id":7 is clicked, then JsonStore: /target/7 should be fetched and get loaded in Gridx.
Issues:
As you can guess, at start there is no valid "id" property to fill in JsonStore. In click event handler of tree, I will get this value, upon a user click. Hence, can't call gridx.startup() in "ready". Though I have "placed" the widget in "ready".
Hence, I have following snippet to handle,
<
// this function is called from tree event handler
function LatestTabGridxLoad( id ) {
console.log( "ID %s fetched.", id );
LatestTabGridxStore.idProperty = id;
LatestTabGridx.startup();
LatestTabGridx.body.refresh();
}
ready(function()
{
TabLatestAssetTree.startup();
LatestTabGridx.placeAt( "ReportMiddleTabLatestCenterContainer" );
}
Now, trouble is, at first time loading, JsonStore GET fired with /target/ alone, without any "id" without any user click. Hence, server responds with 405. Subsequently, when user clicks, again same HTTP GET without "id" results in HTTP 405. I am not able to somehow feed "id" to the GET URL. I have checked JSON, it is in perfect shape, as it works in standalone table, that is declarative(ly) defined.
Please suggest me ways to link a TREE node through its "id" to Gridx. Also suggest, if approach I am taking is right way to solve this problem.
Sorry, misunderstanding of the question. I thought it was about gridx tree but it is about regular gridx controlled by another widget.
The problem is in this line:
console.log( "ID %s fetched.", id );
LatestTabGridxStore.idProperty = id;
'idProperty' is the name of the JSON attribute which stores the ID. This will not change with each selection. If it is not set, JsonStore will assume it to be 'id'. What you intended to do was to modify the target property of the store to include the ID. This can done directly and will look something like the following (details are application specific)
LatestTabGridxStore.target = (someURL) + '/' + id;
After that, the content of gridx needs to be replaced using the new store setting. There are few ways to do it, the simplest being destroying the current gridx instance and replacing it with another one which uses the altered store.

How to assign Custom Activity Result to a Root level variable at Runtime (in Custom Activity Execute method) in workflow?

Assume that I have a workflow with 3 Custom Activities which are placed in a Sequence Activity. And I created a Boolean variable (name it as “FinalResult”) at Sequence Activity level (Root) to hold the Result. My Intention is, I want to assign each Custom Activity Result to Root level variable (“FinalResult”) within the Custom Activity Execute method after finishing the activity.
I can get this by declaring the output argument in Custom Activity and placing the variable name at design time in the properties window of activity manually while designing the policy.
But I don’t want to do this by the end user. I want just the end user drag and drop the activities and write conditions on the” FinalResult” variable. Internally I have to maintain the Activity Result in “FinalResult” Variable through programmatically.
Finally I want to maintain the workflow state in “FinalResult” variable and access it anytime and anywhere in the workflow.
I tried like this below getting error "Property does not exist".
WorkflowDataContext dataContext = context.DataContext;
PropertyDescriptorCollection propertyDescriptorCollection = dataContext.GetProperties();
foreach (PropertyDescriptor propertyDesc in propertyDescriptorCollection)
{
if (propertyDesc.Name == "FinalResult")
{
object data = propertyDesc.GetValue(dataContext);// as WorkUnitSchema;
propertyDesc.SetValue(dataContext, "anil");
break;
}
}
Please let us know the possible solutions for the same.
I do this all the time.
Simply implement IActivityTemplateFactory in your activity. When dragged and dropped onto the design surface, the designer will determine if your activity (or whatever is being dropped) implements this interface. If it does, it will construct an instance and call the Create method.
Within this method you can 1) instantiate your Activity and 2) configure it. Part of configuring it is binding your Activities' properties to other Activities' arguments and/or variables within the workflow.
There are a few ways to do this. Most simply, require these arguments/variables have well known names. In this case, you can simply bind to them via
return new MyActivity
{
MyInArgument = new VisualBasicValue<object>(MyActivity.MyInArgumentDefaultName),
};
where MyActivity.MyInArgumentDefaultName is the name of the argument or variable you are binding to.
Alternatively, if that variable/argument is named by the user... you're in for a world of hurt. Essentially, you have to
Cast the DependencyObject target passed to the Create method to an ActivityDesigner
Get the ModelItem from that AD
Walk up the ModelItem tree until you find the argument/value of the proper type
Use its name to create your VisualBasicValue
Walking up the ModelItem tree is super duper hard. Its kind of like reflecting up an object graph, but worse. You can expect, if you must do this, that you'll have to fully learn how the ModelItem works, and do lots of debugging (write everything down--hell, video it) in order to see how you must travel up the graph, what types you encounter along the way, and how to get their "names" (hint--it often isn't the Name property on the ModelItem!). I've had to develop a lot of custom code to walk the ModelItem tree looking for args/vars in order to implement a drag-drop-forget user experience. Its not fun, and its not perfect. And I can't release that code, sorry.

Resources